Skip to main content

Deployment

Deploy a Nuxt and Convex application with the correct SSR, realtime, and authentication boundaries.

Deploy Convex and Nuxt as two coordinated services. Convex owns the database and functions. Nuxt owns rendering, browser delivery, server routes, and the same-origin auth proxy.

Choose a supported topology

The normal topology is:

  • a Convex cloud deployment;
  • a Nuxt deployment with Nitro server support;
  • one public HTTPS origin for the Nuxt application;
  • browser access to Convex HTTPS and WebSocket endpoints.

Authentication requires an explicit convex.auth object and the generated /api/auth/* Nitro route. A fully static host without Nitro is not a supported auth topology. An app that omits auth can use Nuxt's static output, but only after its own SSR and client-navigation behavior is verified. Use auth: false only when a Nuxt layer must erase inherited auth configuration.

Deployment order

  1. Deploy the Convex schema, functions, HTTP routes, and auth component.
  2. Set the Convex SITE_URL, BETTER_AUTH_SECRETS, and BCN_AUTH_PROXY_IP_SECRET variables. Convex injects its deployment-owned CONVEX_SITE_URL built-in automatically.
  3. Run the internal auth:rotateSigningKey operator action before admitting auth traffic.
  4. Build and deploy Nuxt behind a closed traffic gate, then verify the returned newKid is present in public JWKS.
  5. For delegated OAuth, provision and verify clients, resources, and links through the provider-owned admin API.
  6. Verify the deployed origins and auth ceremony, then open public ingress.
bash
pnpm exec better-convex-nuxt-convex deploy
pnpm build

The owner-only .env.local used here must contain either the intended production deployment's scoped CONVEX_DEPLOY_KEY (or its supported alias) or an exact self-hosted URL/admin-key pair. The checked runner rejects a plain CONVEX_DEPLOYMENT for deploy, because the pinned CLI interprets that value as project context and silently targets the project's production deployment. Inspect the deployment-scoped key immediately before the command. Ambient, sibling-file, project-key, preview-project-key, and command-line target overrides are rejected.

Production checklist

  • Use the exact Node, Nuxt, and Convex tuple in the package manifest. When auth is enabled, install the exact Better Auth and OAuth Provider optional peers explicitly.
  • Set an exact HTTPS SITE_URL without a trailing path and pass that same value as convex.auth.origin.
  • Keep BETTER_AUTH_SECRETS out of Nuxt entirely and keep BCN_AUTH_PROXY_IP_SECRET out of public config and logs.
  • Configure Nuxt's NUXT_PUBLIC_CONVEX_SITE_URL to the exact deployed HTTP Actions origin; do not try to override Convex's built-in CONVEX_SITE_URL.
  • Confirm /api/auth/* reaches the intended .convex.site origin.
  • Permit the exact Convex HTTPS and WebSocket origins in Content Security Policy.
  • Configure convex.auth.trustedClientIpHeader outside exact loopback development and make the ingress overwrite it with exactly one client IP. Missing or malformed values fail closed before Better Auth.
  • Restrict direct access to the Nuxt origin so public traffic can arrive only through that ingress, or independently authenticate ingress requests at the origin. A rewritten header is not a boundary when the origin is bypassable.
  • Keep module logging off unless investigating a specific problem.
  • Exercise sign-in, sign-out, SSR refresh, client navigation, and realtime reconnect.
  • Verify backend authorization with two different users, not only UI visibility.
  • Rehearse social-provider callbacks, recovery, expiry, denial, and rollback for every enabled provider.
  • For delegated OAuth/MCP, also rehearse consent, PKCE, wrong-client/resource/scope rejection, revocation, and live membership removal.

The delegated OAuth and MCP guide defines the pre-traffic key ceremony, fixed topology, deployment order, and forward-fix recovery policy. Do not replace it with first-request key creation or destructive JWKS cleanup.

Preview deployments

An arbitrary preview URL cannot safely reuse production auth configuration. Give stable previews their own Convex deployment, exact SITE_URL, and independent secrets, or disable auth for documentation-style previews. Wildcard trusted origins and shared production secrets weaken the boundary and are not a substitute for isolated environments.

Health checks

A successful HTML response proves only that Nuxt started. Add checks that cover the actual dependency chain:

  • an anonymous Convex query;
  • an authenticated server-rendered page when auth is enabled;
  • a browser subscription receiving a change;
  • the auth proxy rejecting unsupported methods and invalid upstream behavior.

See Security Model before exposing the application publicly.