NuxtHub
Use this guide when you want the shortest path to database-backed auth with schema generation handled by the module.
NuxtHub provides the easiest way to add database persistence to your authentication. Enable NuxtHub and this module generates and manages your database schema.
Features
- Auto Schema Generation - Tables for users, sessions, accounts created automatically
- Plugin-Aware - Schema updates when you add plugins like
twoFactor,passkey - Multi-Dialect - SQLite, PostgreSQL, or MySQL
- Multi-Cloud - Deploy to Cloudflare, Vercel, or self-hosted infrastructure
- Custom Secondary Storage - Optional atomic storage for session caching
- Zero Config Migrations - Use
npx nuxt db migratefor production
Setup
Install NuxtHub
pnpm add @nuxthub/core@^0.10.5
Configure nuxt.config.ts
export default defineNuxtConfig({
modules: [
'@nuxthub/core',
'@nuxtjs/better-auth'
],
hub: {
db: 'sqlite' // 'sqlite' | 'postgresql' | 'mysql'
}
})
Restart Dev Server
The schema is generated at build time. Restart after configuration changes.
Configuration Options
The hub.db option accepts a string shorthand or full object:
export default defineNuxtConfig({
hub: {
db: 'sqlite' // shorthand: 'sqlite' | 'postgresql' | 'mysql'
// or full object:
// db: { dialect: 'postgresql', /* additional options */ }
}
})
Secondary Storage
NuxtHub KV cannot be used as Better Auth 1.7 secondary storage. Better Auth requires atomic getAndDelete for one-time verification values and atomic increment for rate limiting. NuxtHub KV exposes neither operation.
Use a custom backend such as Redis or Upstash that implements the complete atomic contract:
export default defineNuxtConfig({
hub: { db: 'sqlite' },
auth: {
hubSecondaryStorage: 'custom'
}
})
Then provide secondaryStorage in defineServerAuth() with get, getAndDelete, increment, set, and delete methods. getAndDelete and increment must use the backend's atomic operations.
hubSecondaryStorage: true currently logs a setup warning and continues without injecting secondary storage. Without a custom secondary store, sessions use the configured database when one exists and rate limiting defaults to process-local memory. Set the option to false to silence the warning, or switch to 'custom' with an atomic backend.Temporary compatibility fallback
The warning keeps existing applications running while NuxtHub adds atomic KV operations. That work is driver-specific. The module can only restore automatic integration for drivers that provide both getAndDelete and increment.
This fallback does not pretend NuxtHub KV is active. The module records hubSecondaryStorage as false at runtime and generates the database-backed session schema.
Sessions and verification values stored only in KV will no longer be found after deploying this fallback. Users may need to sign in again, and you may need to reissue pending verification links or codes.
In-memory rate-limit counters are not shared between server processes. For shared limits in serverless or multi-instance deployments, set Better Auth's rateLimit.storage to 'database' or provide rateLimit.customStorage.
Choosing Secondary Storage
Set hubSecondaryStorage: 'custom' only when session-read traffic is a measured bottleneck and your backend implements the atomic Better Auth contract. Keep the default false for database-backed sessions.
This setup can introduce a short propagation window after session invalidation events, such as sign-out or permission-sensitive updates. For critical authorization paths, keep server-side checks in place with requireUserSession.
To return to DB-only session reads, set auth.hubSecondaryStorage to false and deploy.
hubSecondaryStorage: true omitted session, upgrading may produce a one-time migration that reintroduces session to match stable schema output.Production Migrations
NuxtHub handles migrations automatically in most deployments. For manual control:
Manual Migration
If you need to run migrations manually:
# Generate migrations from schema changes
npx nuxt db generate
# Apply pending migrations
npx nuxt db migrate
CI/CD Integration
Add to your GitHub Actions workflow:
- name: Run migrations
run: npx nuxt db migrate
env:
NUXT_HUB_PROJECT_KEY: ${{ secrets.NUXTHUB_PROJECT_KEY }}
Schema Generation Details
The module analyzes your server/auth.config.ts at build time:
- Reads plugins from your config
- Generates Drizzle schema matching your dialect
- Injects into NuxtHub via
hub:db:schema:extendhook
buildDir to node_modules/.cache/nuxt/.nuxt, the module mirrors schema.<dialect>.ts to root .nuxt/better-auth/ and uses that mirrored path for NuxtHub schema extension. This avoids Node type-stripping failures for .ts files under node_modules. In normal buildDir layouts, the hook prefers schema.<dialect>.ts and falls back to schema.<dialect>.mjs.Accessing the Database
With NuxtHub, you get access to the Drizzle database instance in your server config:
import { defineServerAuth } from '@nuxtjs/better-auth/config'
export default defineServerAuth(({ db }) => ({
// db is the Drizzle instance from NuxtHub
}))
Creating Custom Tables with Foreign Keys
Create application tables that reference auth tables by importing schema from #auth/schema. This is the stable Better Auth schema export for app queries.
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core'
import { schema } from '#auth/schema'
export const posts = sqliteTable('posts', {
id: text('id').primaryKey(),
title: text('title').notNull(),
authorId: text('author_id').notNull()
.references(() => schema.user.id),
createdAt: integer('created_at', { mode: 'timestamp' })
.$defaultFn(() => new Date()),
})
Available Auth Tables
Reference these tables via the schema object:
schema.user- User accountsschema.session- Active sessionsschema.account- OAuth provider accountsschema.verification- Email verification tokens- Plugin tables:
schema.passkey,schema.twoFactor, etc. (based on enabled plugins)
ID Type Matching
Match your auth table ID types in foreign keys:
- SQLite / MySQL: Use
text()orvarchar() - PostgreSQL with UUID: Use
uuid()whenadvanced.database.generateId = 'uuid'
Migrations
Generate and apply migrations after schema changes:
npx nuxt db generate # Generate migrations
npx nuxt db migrate # Apply (automatic in dev)
server/db/ for NuxtHub to discover them.Adding Columns to Auth Tables
To add fields to existing auth tables (e.g., role on user), use Better Auth's additionalFields instead of custom schemas.