This library is in early development. Expect breaking changes.
Integrations

NuxtHub

Automatic database setup with schema generation and Drizzle ORM integration.

NuxtHub provides the easiest way to add database persistence to your authentication. Enable NuxtHub and this module generates and manages your database schema.

NuxtHub is vendor-agnostic. Deploy to Cloudflare, Vercel, or self-host. See NuxtHub deployment docs.

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
  • Secondary Storage - Optional KV storage for session caching
  • Zero Config Migrations - Use npx nuxt db migrate for production

Setup

Install NuxtHub

pnpm add @nuxthub/core@^0.10.5
Version 0.10.5 or later is required. Earlier versions cause runtime errors in development mode.

Configure nuxt.config.ts

nuxt.config.ts
export default defineNuxtConfig({
  modules: [
    '@nuxthub/core',
    '@onmax/nuxt-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:

nuxt.config.ts
export default defineNuxtConfig({
  hub: {
    db: 'sqlite' // shorthand: 'sqlite' | 'postgresql' | 'mysql'
    // or full object:
    // db: { dialect: 'postgresql', /* additional options */ }
  }
})

Secondary Storage (KV)

Enable KV storage for faster session lookups:

nuxt.config.ts
export default defineNuxtConfig({
  hub: {
    db: 'sqlite',
    kv: true
  },

  auth: {
    hubSecondaryStorage: true
  }
})

Sessions are cached in NuxtHub KV, reducing database queries.

Both hub.kv: true and auth.hubSecondaryStorage: true must be set together. The build will fail with a clear error if hubSecondaryStorage is true without hub.kv.

Choosing Secondary Storage

hubSecondaryStorage: true stores session lookups in NuxtHub KV and can reduce repeated database reads on session validation. SSR requests still resolve session state per request, but lookups can hit KV instead of the database.

With hubSecondaryStorage: true, generated auth schema remains stable and still includes core tables: user, account, session, and verification.

If you want to use a different KV backend (Redis, Upstash, etc.), set hubSecondaryStorage: 'custom' and provide your own secondaryStorage in defineServerAuth() (required; the build fails in production if missing). This is the mode where the module can omit the session table from generated schema and it will not inject NuxtHub KV code.

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.

Enable hubSecondaryStorage when hub.kv is enabled and session-read traffic is a measurable bottleneck. Keep DB-only sessions when your traffic is moderate or when you prioritize stricter read-after-write consistency.

To return to DB-only session reads, set auth.hubSecondaryStorage to false and deploy.

If you previously generated migrations while 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 }}
See NuxtHub Database docs for more details.

Schema Generation Details

The module analyzes your server/auth.config.ts at build time:

  1. Reads plugins from your config
  2. Generates Drizzle schema matching your dialect
  3. Injects into NuxtHub via hub:db:schema:extend hook
Restart Required: After adding/removing plugins that affect database structure, restart the dev server to regenerate the schema.
When Nuxt resolves 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:

server/auth.config.ts
import { defineServerAuth } from '@onmax/nuxt-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.

server/db/schema.ts
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 accounts
  • schema.session - Active sessions
  • schema.account - OAuth provider accounts
  • schema.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() or varchar()
  • PostgreSQL with UUID: Use uuid() when advanced.database.generateId = 'uuid'
See Drizzle schemas for full schema definition guide.

Migrations

Generate and apply migrations after schema changes:

npx nuxt db generate  # Generate migrations
npx nuxt db migrate   # Apply (automatic in dev)
Restart dev server after adding schemas in 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.