nuxt-convex-module
v0.0.0
Published
Convex for Vue & Nuxt — a faithful port of Convex's official React/Next integration (queries, mutations, actions, pagination, file storage, SSR) with opt-in Better Auth and Polar
Maintainers
Readme
nuxt-convex-module
Convex for Vue & Nuxt — a faithful Vue/Nuxt port of Convex's official React/Next integration.
nuxt-convex-module mirrors the upstream convex/react + convex/nextjs surface composable-for-hook: reactive live queries, mutations, actions, cursor pagination, file storage, connection state, and SSR preloading — adapted to Vue with VueUse conventions (MaybeRefOrGetter inputs, ComputedRef/ShallowRef returns). Authentication is provider-agnostic like upstream: the core ships the generic ConvexProviderWithAuth equivalent (provideConvexAuth) plus Vue ports of Convex's Clerk and Auth0 adapters, while Better Auth and Polar are opt-in sub-modules — mirroring how @convex-dev/better-auth and @convex-dev/polar are separate packages upstream.
📖 Full documentation: the docs site (homepage · docs · playground, one Nuxt app) covers installation, the integration guide, every composable and server helper, and the complete API reference.
Supported official packages
Every supported upstream package is ported or wired with the same public API, adapted to Vue. Core Convex is always on; the rest light up when their package is installed.
| Official package | What this gives you | Enable | Subpath | Baseline |
|---|---|---|---|---|
| convex — /react + /nextjs | The whole data layer: composables, ConvexVueClient, auth helpers, SSR preload + server (Nitro) utils | always on | …/vue, …/server | 1.42 |
| convex — /react-clerk | Clerk auth: provideConvexAuthFromClerk() · <ConvexProviderWithClerk> | npm i @clerk/vue | …/clerk/vue | 1.42 |
| convex — /react-auth0 | Auth0 auth: provideConvexAuthFromAuth0() · <ConvexProviderWithAuth0> | npm i @auth0/auth0-vue | …/auth0/vue | 1.42 |
| @convex-dev/better-auth | Better Auth: useAuth, /api/auth/** proxy, SSR prefetch, auth middleware, <AuthBoundary>, convexAuth | npm i @convex-dev/better-auth | …/better-auth/vue | 0.12 |
| @convex-dev/polar | Polar billing: <CheckoutLink> · <CustomerPortalLink> | npm i @convex-dev/polar | …/polar/vue | 0.9 |
| @convex-dev/resend | Server-only — no client port needed; call its functions with useMutation / useAction | (use in your Convex deployment) | — | — |
Subpath = nuxt-convex-module/<subpath>. Pinned baselines and the file-by-file map: PARITY.md.
How it plugs into Nuxt
Listing nuxt-convex-module in your modules array wires Convex into every layer of the app — through the same @nuxt/kit integration points any module uses. Everything below is registered for you; nothing needs importing or manual wiring.
Auto-imported composables · addImports
Data
useQuery/useConvexQuery— reactive live query (plususeQuery_experimental, the 1.39 result/error split)useAsyncQuery/useConvexAsyncQuery— SSR-fetched, payload-hydrated live query with Nuxt's{ data, error, status, refresh }shapeuseQueries/useConvexQueries— several live queries over one subscriptionuseMutation/useConvexMutation— call a Convex mutationuseAction/useConvexAction— call a Convex actionusePaginatedQuery— cursor pagination (plususePaginatedQuery_experimental, dual-overload)useConvexConnectionState— live WebSocket connection statususeConvex— the underlying Convex client
Files
useUpload/useConvexUpload/uploadFile— upload to Convex storageuseUploadQueue/useConvexUploadQueue— multi-file upload queueuseStorageUrl/useConvexStorageUrl— resolve a stored file's URL
Auth (provider-agnostic)
useConvexAuth/provideConvexAuth— Convex auth stateusePreloadedQuery— hydrate an SSR-preloaded query on the client
App API wiring
provideConvexApi/useConvexApi/useConvexNamespace— provide and consume the generatedapi
Auto-imported components · addComponent
<Authenticated>/<Unauthenticated>/<AuthLoading>/<AuthRefreshing>— render by auth state
Integration-specific composables and components auto-import too when their package is installed —
useAuth+<AuthBoundary>(Better Auth),provideConvexAuthFromClerk+<ConvexProviderWithClerk>(Clerk),provideConvexAuthFromAuth0+<ConvexProviderWithAuth0>(Auth0),<CheckoutLink>+<CustomerPortalLink>(Polar). See Supported official packages.
Server (Nitro) auto-imports · addServerImports
fetchQuery/fetchMutation/fetchAction— one-shot Convex callspreloadQuery/preloadedQueryResult— SSR preload and the client hydration handoffconvexAuth— request-scoped authenticated server client (Better Auth only)
Plugins, middleware & dev wiring
- Base client plugin ·
addPlugin— provides aConvexVueClient(server + client) so the data layer works on its own; Better Auth supplies its own client plugin instead when installed. - Provide-api plugin ·
addPluginTemplate— wires the generatedapiapp-wide; fs-guarded to a no-op untilconvex devhas run, and re-rendered live the moment codegen appears (builder:watch). - Server handler + route rule ·
addServerHandler/extendRouteRules— the same-origin/api/auth/**proxy, marked uncacheable (Better Auth only). - Route middleware ·
addRouteMiddleware— the opt-inauthpage guard (Better Auth only). - Nuxt DevTools tab ·
addCustomTab+ devtools RPC — a Convex panel (dev only): live connection state, active query subscriptions with results and per-query server logs, auth state, the client log stream, and open-in-editor for Convex functions. Disable withconvex.devtools: false.
Runtime config & import aliases
- Runtime config (
convexkey, viaupdateRuntimeConfig): publicconvex.url/convex.siteUrl - Aliases (Vite + Nitro):
#convex,#convex/api,#convex/server,#convex/dataModel,#convex/_generated
Module dependency · moduleDependencies
- Installs and configures
nuxt-security, applying a Convex-aware CSP in production —connect-src,img-src, andmedia-srcscoped to your deployment.
Manual imports · subpath exports
Everything above is auto-imported in Nuxt, but each surface is also a real subpath export — reach for these for explicit/type-only imports. Entries follow client/server naming. The self-contained client entries also work in a plain Vue (non-Nuxt) app and carry a /vue alias for that use; /better-auth/client and /server rely on Nuxt-provided aliases/runtime config and need Nuxt:
| Import path | Contents |
|---|---|
| nuxt-convex-module | the Nuxt module (for modules: []) |
| nuxt-convex-module/client (alias /vue) | ConvexVueClient, ConvexClientKey, every composable (useQuery, useMutation, useAction, pagination, upload, …), auth (provideConvexAuth, useConvexAuth, <Authenticated> …), usePreloadedQuery, and all public types |
| nuxt-convex-module/server | Nitro/server: fetchQuery, fetchMutation, fetchAction, preloadQuery, preloadedQueryResult |
| nuxt-convex-module/clerk/client (alias /clerk/vue) | provideConvexAuthFromClerk, <ConvexProviderWithClerk> |
| nuxt-convex-module/auth0/client (alias /auth0/vue) | provideConvexAuthFromAuth0, <ConvexProviderWithAuth0> |
| nuxt-convex-module/better-auth/client | useAuth, authClient, usePreloadedAuthQuery, consumeCrossDomainOneTimeToken, <AuthBoundary>, and the convexClient / crossDomainClient client plugins (re-exported from @convex-dev/better-auth/client/plugins) |
| nuxt-convex-module/better-auth/server | Nitro/server: convexAuth(event) (auto-imported in server code; import explicitly for the ConvexAuthOptions / ConvexAuthService types) |
| nuxt-convex-module/polar/client (alias /polar/vue) | <CheckoutLink>, <CustomerPortalLink> |
Integrations (auto-detected)
You only ever add one module. Better Auth and Polar light up automatically when their packages are installed — no extra modules entries, no config:
# add auth → it's wired on next dev
npm i @convex-dev/better-auth better-auth
# add billing components → registered automatically
npm i @convex-dev/polar @polar-sh/checkout// nuxt.config.ts — still just one module
export default defineNuxtConfig({
modules: ['nuxt-convex-module'],
// Everything below is optional. Integrations auto-enable when installed;
// override only if you want to force one on/off or change the auth route.
convex: {
// betterAuth: false,
// betterAuth: { authClient: './app/convex-auth-client' }, // bring your own client
// betterAuth: { crossDomainCallbackRoute: '/auth/callback' }, // login-CSRF guard for crossDomainClient()
// polar: false,
// authRoute: '/api/auth',
},
})- Better Auth (when
@convex-dev/better-authis installed) — a Vue/Nuxt port of itsreact+nextjsintegration:useAuth(session, sign-in/out), the same-origin/api/auth/**proxy, SSR token prefetch, the opt-inauthroute middleware, the<AuthBoundary>component, andconvexAuth(event)for request-scoped server calls. Imported directly vianuxt-convex-module/better-auth/client. Bring your own auth client (to choose plugins — e.g.emailOTPClient(),passkeyClient(), orcrossDomainClient()for cross-domain auth) by pointingconvex.betterAuth.authClientat a module that exportsauthClient; otherwise a minimal bundled default (convexClient()only) is used. - Clerk (when
@clerk/vueis installed) — a Vue port ofconvex/react-clerk:provideConvexAuthFromClerk()and<ConvexProviderWithClerk>. Types vianuxt-convex-module/clerk/client. - Auth0 (when
@auth0/auth0-vueis installed) — a Vue port ofconvex/react-auth0:provideConvexAuthFromAuth0()and<ConvexProviderWithAuth0>. Types vianuxt-convex-module/auth0/client. - Polar (when
@convex-dev/polaris installed) — a Vue port of@convex-dev/polar/react's<CheckoutLink>and<CustomerPortalLink>. Types vianuxt-convex-module/polar/client.
Pure Convex with no auth? Install none of them — you get just the data layer (the module provides a base client on its own), and nothing drags an auth provider or Polar into your bundle.
Quick start
1. Install
npx nuxi@latest module add nuxt-convex-moduleUsing strict pnpm? Add
public-hoist-pattern[]=@convex-dev/*to.npmrc(or setnode-linker=hoisted) so Convex can resolve component definitions.
2. Add the module
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['nuxt-convex-module'],
})3. Configure environment
# .env.local (Nuxt app)
NUXT_PUBLIC_CONVEX_URL=https://your-deployment.convex.cloud
NUXT_PUBLIC_CONVEX_SITE_URL=https://your-deployment.convex.site4. Start the app, then Convex
npm run dev
npx convex devA taste
<script setup lang="ts">
import { api } from '#convex/api'
// SSR-rendered AND live-updating — Nuxt's { data, status, error } shape:
const { data: messages } = useAsyncQuery(api.messages.list, {})
const send = useMutation(api.messages.send)
</script>
<template>
<ul><li v-for="m in messages" :key="m._id">{{ m.body }}</li></ul>
<button @click="send({ body: 'hi' })">Send</button>
</template>A runnable version lives in examples/minimal — or open it directly in StackBlitz.
Relationship to upstream
This package is intentionally kept diffable against the upstream React/Next sources so it can track new Convex / Better Auth / Polar releases. Each file mirrors its origin:
| This package | Upstream |
|---|---|
| src/runtime/vue/** | convex/src/react/** |
| src/runtime/nuxt/** | convex/src/nextjs/** |
| src/runtime/clerk/** | convex/src/react-clerk/** |
| src/runtime/auth0/** | convex/src/react-auth0/** |
| src/runtime/better-auth/** | @convex-dev/better-auth/src/{react,nextjs}/** |
| src/runtime/polar/** | @convex-dev/polar/src/react/** |
The authoritative file-by-file map, pinned upstream baseline versions, and out-of-scope list live in PARITY.md; the React→Vue translation rules an automated sync agent follows are in AGENTS.md.
Contributing
- Clone this repository
- Install dependencies using
pnpm install - Prepare for development using
pnpm dev:prepare - Start the development server (the docs/playground app) using
pnpm dev— orpnpm start
pnpm dev runs the playground through portless, so it is served at a stable, named HTTPS URL — https://nuxt-convex-module.localhost — instead of a shifting localhost:<port>. portless generates and trusts a local CA on first run (auto-elevating to bind port 443); pass --no-tls for plain HTTP, or run nuxt dev website directly to bypass portless entirely.
We follow conventional commits. See CONTRIBUTING.md and RELEASING.md.
Security
Found a vulnerability? Report it privately via GitHub Security Advisories — not in a public issue. See SECURITY.md.
