The all-in-one SaaS backend for Nuxt on Convex — auth (Better Auth, passwordless: OTP + passkeys), workspaces with emailed invitations end-to-end, billing (Polar) with feature gating, prepaid credits, and gift purchases, transactional email (Resend) with delivery tracking, one-call webhook wiring, rate limiting, durable workflows, migrations, aggregates, and full-text search. One module, great defaults, every setting customizable.
It even ships the pages: /login, /pricing, /settings, /profile, /security, and /accept-invitation mount out of the box — headless components with a neutral stylesheet, customizable at every level (CSS tokens → app.config content → slots → shadow the route with your own page) without ever ejecting.
nuxt-backend ships two halves that work as one:
- a Nuxt module — the SaaS composables, scaffolding, env preflight, and
#backend/*aliases; and - a Convex backend — a preassembled app definition (
defineBackendApp) that mounts the package's all-in-onebackendcomponent (auth tables + adapter, email with the provider component nested inside, the billing entitlement cache, and gifts) plus the upstream Polar, rate limiter, workflow, migrations, and aggregate components for you.
The generic Convex ⇄ Nuxt integration underneath (live queries, mutations, SSR, auth plumbing, DevTools, Convex-aware CSP) comes from nuxt-convex-module — installed and configured automatically. Use that package directly if you only want Convex bindings without the SaaS layer.
📖 Full documentation: the docs site (homepage · docs · playground, one Nuxt app) covers installation, every composable, the bundled backend components, and the complete API reference.
npx nuxi@latest module add nuxt-backendThis is the only package you install — the Convex integration and all bundled components ship as its dependencies.
Using strict pnpm? Add
public-hoist-pattern[]=@convex-dev/*to.npmrc(or setnode-linker=hoisted) so Convex can resolve the bundled component definitions. See the installation docs.
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['nuxt-backend'],
})# .env.local (Nuxt app)
NUXT_PUBLIC_CONVEX_URL=https://your-deployment.convex.cloud
NUXT_PUBLIC_CONVEX_SITE_URL=https://your-deployment.convex.siteAll nine Convex deployment variables are required — a deploy fails until every one is set, so misconfiguration surfaces at push time instead of in production:
# Convex deployment
npx convex env set AUTH_SECRET "$(openssl rand -base64 32)"
npx convex env set SITE_URL https://your-app.localhost
# email (powered by Resend)
npx convex env set EMAIL_API_KEY re_...
npx convex env set EMAIL_FROM "Acme <hello@yourdomain.com>"
npx convex env set EMAIL_TEST_MODE true
npx convex env set EMAIL_WEBHOOK_SECRET whsec_...
# billing (powered by Polar)
npx convex env set BILLING_ACCESS_TOKEN ...
npx convex env set BILLING_WEBHOOK_SECRET ...
npx convex env set BILLING_ENVIRONMENT sandbox # or productionnpm run dev # first run scaffolds the Convex files under convex/
npx convex devThat's it — sign in with useAuth(), read live data with useQuery, gate features with useFeatures, and protect pages with the auth middleware.
<script setup lang="ts">
import { api } from '#backend/api'
definePageMeta({ middleware: 'auth' })
const { user, sendOtp, signInWithPasskey } = useAuth()
const { isSubscribed, checkout } = useBilling()
const messages = useQuery(api.messages.list, {})
</script>Listing nuxt-backend in modules registers everything below — nothing needs importing or manual wiring.
SaaS layer (this package)
useAuth— session + the passwordless flows:signOut,sendOtp,signInWithOtp,signInWithPasskey,registerPasskey,changeEmail,deleteAccount; the fully-typed Better Authclientfor everything elseuseOrganization— workspaces + the full invitation flow:invite,acceptInvitation,declineInvitation,cancelInvitation,getInvitation,listReceivedInvitationsuseBilling— subscription state,checkout,gift,portal,changePlan,canceluseFeatures— entitlement / feature flags from active subscriptionsuseCredits— prepaid credit balances +topUpandgiftuseGifts— gifts addressed to the signed-in user, auto-claimed on first sign-in (or explicitclaim)useEmailStatus— live email delivery statususeWorkflowStatus— workflow run statususeSearch— debounced full-text searchuseAggregate/useCount— aggregate-component reads
Core (from nuxt-convex-module) — useQuery, useQueries, useMutation, useAction, usePaginatedQuery, usePreloadedQuery, useConvexAuth, useConvexConnectionState, useUpload, useUploadQueue, useStorageUrl, useConvex, and friends.
<Authenticated> / <Unauthenticated> / <AuthLoading> / <AuthBoundary> — render by auth state · <RoleBoundary> / <FeatureBoundary> — gate UI by role or billing entitlement · <AcceptInvitation> — the workspace-invitation accept/decline UI (also served by the auto-registered /accept-invitation page) · <GiftClaimBanner> — surface unclaimed gifts · <CheckoutLink> / <CustomerPortalLink> — billing links
fetchQuery / fetchMutation / fetchAction · preloadQuery / preloadedQueryResult · convexAuth(event) — an authenticated, request-scoped Convex client. Plus the same-origin /api/auth/** Better Auth proxy and the opt-in auth route middleware.
#backend, #backend/api, #backend/server, #backend/dataModel, #backend/_generated — typed imports for your Convex functions dir (fallback types keep a fresh project compiling before the first convex dev).
On dev startup the module checks your environment — missing site URL, weak AUTH_SECRET, malformed SITE_URL — and prints actionable hints. The Convex deployment itself enforces the full env at push time: a deploy fails until every required variable is set.
nuxt-convex-module (the Convex integration, with Better Auth + Polar force-enabled and this package's passwordless auth client) and nuxt-security (Convex-aware CSP in production) are installed as true module dependencies — deduplicated if your app lists them too, configurable through their own convex / security keys.
The scaffolded convex/ files compose the backend from nuxt-backend/*:
defineBackendApp— mounts the all-in-onebackendcomponent (auth + email + billing cache + gifts, with the email provider nested inside) plus the upstream Polar, rate limiter, workflow, migrations, and aggregate components, declares the required env vars, and forwards the email configsetupAuth— passwordless Better Auth (OTP + passkey plugins), workspaces with emailed invitations, email templates includedsetupBilling— products, checkout, webhook handlers, entitlement cache, prepaid credits (spendCredits), and gift purchases (giftCheckout/claimGift)registerBackendRoutes— one call mounts every inbound webhook: auth routes,/billing/events,/email/eventssetupEmail,setupRateLimiter,setupWorkflows,setupMigrations,withTriggers(aggregates),defineSearch
The site (homepage · docs · playground) lives in website/:
cd website
pnpm dev # local preview at http://localhost:3000
pnpm generate # static build| Section | What's inside |
|---|---|
| Getting Started | Introduction, installation, configuration, architecture |
| Guide | Auth, queries & mutations, server & SSR, file storage, import aliases |
| Backend Components | Email, billing & credits, rate limiting, workflows, migrations, aggregates, search |
| Convex Backend | Auth setup, customizing auth, local installation, testing |
| API Reference | Composables, server utilities, client, entrypoints, module options |
examples/minimal— the exactnuxt-backend initscaffold, zero custom backend code: passwordless auth, workspace invitations, billing, credits, and gifts out of the boxexamples/advanced— every customization point in one app: local component install, custom email templates, custom webhook paths and hooks, a hand-writtendefineApp+installBackend, and a custom invitation accept page
- Clone this repository (and its sibling
nuxt-convex-modulenext to it — linked vialink:../nuxt-convex-module) - Install dependencies using
pnpm install(in both repos; runpnpm dev:prepareinnuxt-convex-moduleonce) - Prepare for development using
pnpm dev:prepare - Start development server using
pnpm dev
We follow conventional commits (Dependabot PRs do too). See CONTRIBUTING.md and RELEASING.md for the full workflow.
Found a vulnerability? Report it privately via GitHub Security Advisories — not in a public issue. See SECURITY.md.