Limitations and Trade-offs
Understand the runtime costs, deliberate constraints, and unsupported cases before adopting the module.
Better Convex Nuxt removes integration work by choosing a defined lifecycle. Those choices have costs.
SSR plus live data performs two stages
The default query performs:
- An HTTP query during SSR.
- A WebSocket subscription in the browser.
Both stages serve a purpose. The first produces initial HTML; the second keeps data live. They may appear as two query executions in the Convex dashboard and both contribute to application work.
Disable SSR for browser-only data:
useConvexQuery(api.notifications.list, {}, { server: false })Live browser observation is a transport invariant. For a one-shot operation, call a query through the restricted useConvex() handle or from a request-scoped server boundary instead of creating composable state.
Authentication depends on the integration
The Nuxt package's built-in full-stack authentication runtime is designed around Better Auth and its deployment-owned Convex component. Another Nuxt provider requires an application-owned integration or another library.
The plain Vue package instead accepts a provider-neutral browser auth adapter. That adapter owns provider state and token acquisition; Better Convex owns identity fencing and the Convex client lifecycle. This does not turn provider sessions, token scopes, or UI capability state into application authorization.
Omit convex.auth when the application does not use authentication. This removes auth-only plugins, proxy handlers, middleware, and Better Auth runtime code from the build graph. Use auth: false only to erase inherited auth configuration in a Nuxt layer.
Product authorization remains yours
The module can determine whether a Convex identity is available. It cannot know whether that identity may edit a project, administer an organization, or read a document.
Enforce those rules inside Convex functions. Route middleware and conditional components are UX controls.
Schema-changing auth plugins require more setup
Better Auth plugins such as organizations, admin, API keys, and two-factor authentication can change the component schema and client API. They require matching server configuration, schema generation, local component registration, and a typed client definition. Run better-convex-nuxt-auth-schema to regenerate the checked-in schema and metadata pair from the build-only plugin options.
The module does not make an arbitrary Better Auth plugin compatible automatically.
The raw Convex client is not public
useConvex() returns exactly query, mutation, action, and onUpdate. It does not expose setAuth, clearAuth, connectionState, or close.
This constraint lets the runtime replace an identity-scoped client without leaving application code with a closed reference. Use useConvexConnectionState() for connection observation.
Query state is scope-owned state
Each query composable owns its Vue-visible state for the current effect scope. Convex may deduplicate identical wire work, but there is no cross-request application cache and no data reuse across identities.
Convex owns server-backed query data. Use Pinia or local state for UI-only concerns, not as a mirror of Convex entities.
Awaiting is optional
Nuxt query state exists immediately and is also a native Promise for initial settlement. Await only when surrounding setup needs that barrier. Query failures resolve into status and error; skipped and browser-only queries also resolve instead of rejecting navigation.
Exact versions are intentional
The package pins Nuxt, Convex, Better Auth, and its package-owned OAuth Provider runtime exactly. This makes lifecycle and security behavior testable, but requires coordinated dependency upgrades.
The auth hard cut is greenfield
The integrated component is not an in-place upgrade tool for a populated auth database. It intentionally has no compatibility adapter, dual schema, identity converter, or migration path. Start with a fresh component database and one component mounted as betterAuth.
Delegated OAuth is deliberately narrow
The first delegated-agent profile supports preregistered confidential web clients and preregistered public agent clients, authorization code, mandatory PKCE S256, explicit consent, one registered resource, and short-lived access tokens. Public clients use token endpoint authentication method none and never receive a shared secret. Refresh tokens, dynamic registration, client credentials, DPoP, multi-resource tokens, and outbound OIDC identity-provider behavior remain disabled until separately designed and tested.
Enterprise OIDC SSO is a later product phase. Do not model it as the current OAuth authorization-server feature.
Follow the complete delegated OAuth and MCP profile. Its fixed topology and disabled capabilities are part of the supported security contract, not defaults to loosen for client compatibility.
Read release compatibility before overriding versions.