Advanced

Logging

Configure module logging for debugging SSR, auth, queries, and real-time subscriptions.

Quick Start

Enable logging in your nuxt.config.ts:

nuxt.config.ts
export default defineNuxtConfig({
  modules: ['better-convex-nuxt'],

  convex: {
    url: process.env.CONVEX_URL,
    logging: {
      enabled: true, // Enable logging
    },
  },
})

Configuration

OptionTypeDefaultDescription
logging.enabledboolean | 'debug'falseEnable logging (true = info, 'debug' = verbose)
logging.format'pretty' | 'json''pretty'Output format

Logging Levels

nuxt.config.ts
convex: {
  logging: {
    // false - No logs (production default)
    // true - Info-level canonical events
    // 'debug' - Include debug-level details
    enabled: process.env.NODE_ENV === 'development' ? 'debug' : false,
  },
}

Output Formats

Pretty format (default) - Human-readable, ideal for development:

[better-convex-nuxt] > plugin:init [ok] client 47ms | url: happy-dog-123.convex.cloud, auth: enabled
[better-convex-nuxt] * auth:change loading -> authenticated | trigger: ssr-hydration, user: abc12345
[better-convex-nuxt] > query [ok] api.users.get 23ms (cached)
[better-convex-nuxt] > mutation [err] api.posts.create 156ms | error: ConvexError "Unauthorized", retriable

JSON format - Structured output for log aggregation systems:

nuxt.config.ts
convex: {
  logging: {
    enabled: true,
    format: 'json',
  },
}
{"timestamp":"2025-01-09T12:00:00.000Z","event":"plugin:init","env":"client","duration_ms":47,"outcome":"success","config":{"url":"happy-dog-123.convex.cloud","auth":true}}
{"timestamp":"2025-01-09T12:00:00.050Z","event":"auth:change","env":"client","from":"loading","to":"authenticated","trigger":"ssr-hydration","user_id":"abc12345"}
{"timestamp":"2025-01-09T12:00:00.073Z","event":"operation:complete","env":"client","type":"query","name":"api.users.get","duration_ms":23,"outcome":"success","cached":true}

Event Types

The module emits canonical log events - one rich event per significant operation containing all context needed to debug issues.

plugin:init

Emitted when the Convex plugin initializes on client or server:

{
  "event": "plugin:init",
  "env": "client",
  "config": { "url": "...", "siteUrl": "...", "authEnabled": true },
  "duration_ms": 47,
  "outcome": "success"
}

auth:change

Emitted when authentication state changes:

{
  "event": "auth:change",
  "env": "client",
  "from": "loading",
  "to": "authenticated",
  "user_id": "abc12345",
  "trigger": "ssr-hydration"
}

Triggers: init, login, logout, token-refresh, ssr-hydration

operation:complete

Emitted when a query, mutation, or action completes:

{
  "event": "operation:complete",
  "env": "client",
  "type": "mutation",
  "name": "api.posts.create",
  "duration_ms": 156,
  "outcome": "success",
  "optimistic": true,
  "args_preview": "{\"title\":\"Hello...\"}"
}

On error:

{
  "event": "operation:complete",
  "env": "server",
  "type": "query",
  "name": "api.users.get",
  "duration_ms": 45,
  "outcome": "error",
  "error": {
    "type": "ConvexError",
    "message": "Unauthorized",
    "retriable": false
  }
}

subscription:change

Emitted when a real-time subscription changes state:

{
  "event": "subscription:change",
  "env": "client",
  "name": "api.posts.list",
  "state": "subscribed",
  "cache_hit": false
}

On unsubscribe:

{
  "event": "subscription:change",
  "env": "client",
  "name": "api.posts.list",
  "state": "unsubscribed",
  "updates_received": 42
}

States: subscribed, unsubscribed, error, reconnecting

connection:change

Emitted when WebSocket connection state changes:

{
  "event": "connection:change",
  "from": "Disconnected",
  "to": "Connected"
}

On reconnection:

{
  "event": "connection:change",
  "from": "Disconnected",
  "to": "Connected",
  "retry_count": 3,
  "offline_duration_ms": 5000
}

ssr:hydration

Emitted on the client when SSR state is hydrated:

{
  "event": "ssr:hydration",
  "outcome": "match",
  "queries_hydrated": 0,
  "auth_state_match": true,
  "duration_ms": 2
}

On mismatch (e.g., auth token present but user data missing):

{
  "event": "ssr:hydration",
  "outcome": "mismatch",
  "queries_hydrated": 0,
  "auth_state_match": false,
  "mismatch_details": ["token present but user missing"],
  "duration_ms": 1
}

Common Debugging Scenarios

SSR Issues

Enable logging and look for plugin:init events on both server and client:

[better-convex-nuxt] > plugin:init [ok] server 120ms | url: happy-dog-123.convex.cloud, auth: enabled
[better-convex-nuxt] > plugin:init [ok] client 47ms | url: happy-dog-123.convex.cloud, auth: enabled

If the server init fails, check your CONVEX_URL environment variable.

Authentication Flow

Track auth state transitions:

[better-convex-nuxt] * auth:change loading -> unauthenticated | trigger: init
[better-convex-nuxt] * auth:change unauthenticated -> authenticated | trigger: login, user: abc12345

Query Performance

Monitor operation timing:

[better-convex-nuxt] > query [ok] api.posts.list 230ms
[better-convex-nuxt] > query [ok] api.posts.list 12ms (cached)

The (cached) indicator shows when data comes from an existing subscription.

Subscription Lifecycle

Track real-time subscription health:

[better-convex-nuxt] ~ subscription api.posts.list subscribed
[better-convex-nuxt] ~ subscription api.posts.list unsubscribed, updates: 15

Connection Issues

Monitor WebSocket connectivity:

[better-convex-nuxt] || connection Connected -> Disconnected
[better-convex-nuxt] || connection Disconnected -> Connected, retry: 2, offline: 3500ms

Production Usage

For production, use JSON format and send logs to your aggregation system:

nuxt.config.ts
export default defineNuxtConfig({
  convex: {
    logging: {
      // Enable in production only if needed for debugging
      enabled: process.env.CONVEX_LOGGING === 'true',
      format: 'json',
    },
  },
})

The structured JSON output integrates with tools like:

  • Datadog
  • Logtail
  • Axiom
  • Grafana Loki
  • CloudWatch Logs

Best Practices

  1. Development: Use enabled: 'debug' with format: 'pretty' for maximum visibility
  2. Production: Keep enabled: false by default, enable via environment variable when debugging
  3. Log aggregation: Use format: 'json' for structured logging systems
  4. Performance: Logging is a no-op when disabled - no runtime overhead