nuxthub

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

NuxtHub v0.10.6

NuxtHub v0.10.6

Full-stack Nuxt framework with database, KV, blob, and cache. Multi-cloud support (Cloudflare, Vercel, Deno, Netlify).
For Nuxt server patterns: use
nuxt
skill (server.md) For content with database: use
nuxt-content
skill
全栈Nuxt框架,内置数据库、KV、Blob和缓存功能。支持多云部署(Cloudflare、Vercel、Deno、Netlify)。
针对Nuxt服务端模式: 使用
nuxt
技能(server.md) 针对含数据库的内容: 使用
nuxt-content
技能

Loading Files

加载文件

Consider loading these reference files based on your task:
  • references/wrangler-templates.md - if manually configuring wrangler.jsonc for Cloudflare deployment
  • references/providers.md - if deploying to Vercel, Netlify, Deno, AWS, or configuring external database/storage providers
DO NOT load all files at once. Load only what's relevant to your current task.
根据你的任务考虑加载以下参考文件:
  • references/wrangler-templates.md - 若手动配置wrangler.jsonc用于Cloudflare部署
  • references/providers.md - 若部署到Vercel、Netlify、Deno、AWS,或配置外部数据库/存储提供商
不要一次性加载所有文件。只加载与当前任务相关的文件。

Installation

安装

bash
npx nuxi module add hub
bash
npx nuxi module add hub

Configuration

配置

ts
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@nuxthub/core'],
  hub: {
    db: 'sqlite', // 'sqlite' | 'postgresql' | 'mysql'
    kv: true,
    blob: true,
    cache: true,
    dir: '.data', // local storage directory
    remote: false // use production bindings in dev (v0.10+)
  }
})
ts
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@nuxthub/core'],
  hub: {
    db: 'sqlite', // 'sqlite' | 'postgresql' | 'mysql'
    kv: true,
    blob: true,
    cache: true,
    dir: '.data', // local storage directory
    remote: false // use production bindings in dev (v0.10+)
  }
})

Advanced Config

高级配置

ts
hub: {
  db: {
    dialect: 'postgresql',
    driver: 'postgres-js', // Optional: auto-detected
    casing: 'snake_case',  // camelCase JS -> snake_case DB (v0.10.3+)
    migrationsDirs: ['server/db/custom-migrations/'],
    applyMigrationsDuringBuild: true, // default
    replica: { // Read replica support (v0.10.6+)
      connection: { connectionString: process.env.DATABASE_REPLICA_URL }
    }
  },
  remote: true // Use production Cloudflare bindings in dev (v0.10+)
}
remote mode: When enabled, connects to production D1/KV/R2 during local development instead of local emulation. Useful for testing with production data.
Database replica (v0.10.6+): Configure read replicas to distribute database load. Queries use replicas automatically while writes go to primary.
ts
hub: {
  db: {
    dialect: 'postgresql',
    driver: 'postgres-js', // Optional: auto-detected
    casing: 'snake_case',  // camelCase JS -> snake_case DB (v0.10.3+)
    migrationsDirs: ['server/db/custom-migrations/'],
    applyMigrationsDuringBuild: true, // default
    replica: { // Read replica support (v0.10.6+)
      connection: { connectionString: process.env.DATABASE_REPLICA_URL }
    }
  },
  remote: true // Use production Cloudflare bindings in dev (v0.10+)
}
remote模式: 启用后,本地开发时会连接到生产环境的D1/KV/R2,而非本地模拟环境。适用于使用生产数据进行测试。
数据库副本(v0.10.6+): 配置只读副本以分散数据库负载。查询会自动使用副本,而写入操作则指向主数据库。

Database

数据库

Type-safe SQL via Drizzle ORM.
db
and
schema
are auto-imported on server-side.
通过Drizzle ORM实现类型安全的SQL。
db
schema
会在服务端自动导入。

Schema Definition

模式定义

Place in
server/db/schema.ts
or
server/db/schema/*.ts
:
ts
// server/db/schema.ts (SQLite)
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core'

export const users = sqliteTable('users', {
  id: integer().primaryKey({ autoIncrement: true }),
  name: text().notNull(),
  email: text().notNull().unique(),
  createdAt: integer({ mode: 'timestamp' }).notNull()
})
PostgreSQL variant:
ts
import { pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core'

export const users = pgTable('users', {
  id: serial().primaryKey(),
  name: text().notNull(),
  email: text().notNull().unique(),
  createdAt: timestamp().notNull().defaultNow()
})
放置在
server/db/schema.ts
server/db/schema/*.ts
中:
ts
// server/db/schema.ts (SQLite)
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core'

export const users = sqliteTable('users', {
  id: integer().primaryKey({ autoIncrement: true }),
  name: text().notNull(),
  email: text().notNull().unique(),
  createdAt: integer({ mode: 'timestamp' }).notNull()
})
PostgreSQL版本:
ts
import { pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core'

export const users = pgTable('users', {
  id: serial().primaryKey(),
  name: text().notNull(),
  email: text().notNull().unique(),
  createdAt: timestamp().notNull().defaultNow()
})

Database API

数据库API

ts
// db and schema are auto-imported on server-side
import { db, schema } from 'hub:db'

// Select
const users = await db.select().from(schema.users)
const user = await db.query.users.findFirst({ where: eq(schema.users.id, 1) })

// Insert
const [newUser] = await db.insert(schema.users).values({ name: 'John', email: 'john@example.com' }).returning()

// Update
await db.update(schema.users).set({ name: 'Jane' }).where(eq(schema.users.id, 1))

// Delete
await db.delete(schema.users).where(eq(schema.users.id, 1))
ts
// db and schema are auto-imported on server-side
import { db, schema } from 'hub:db'

// Select
const users = await db.select().from(schema.users)
const user = await db.query.users.findFirst({ where: eq(schema.users.id, 1) })

// Insert
const [newUser] = await db.insert(schema.users).values({ name: 'John', email: 'john@example.com' }).returning()

// Update
await db.update(schema.users).set({ name: 'Jane' }).where(eq(schema.users.id, 1))

// Delete
await db.delete(schema.users).where(eq(schema.users.id, 1))

Migrations

迁移

bash
npx nuxt db generate                  # Generate migrations from schema
npx nuxt db migrate                   # Apply pending migrations
npx nuxt db sql "SELECT * FROM users" # Execute raw SQL
npx nuxt db drop <TABLE>              # Drop a specific table
npx nuxt db drop-all                  # Drop all tables (v0.10+)
npx nuxt db squash                    # Squash migrations into one (v0.10+)
npx nuxt db mark-as-migrated [NAME]   # Mark as migrated without running
Migrations auto-apply during
npx nuxi dev
and
npx nuxi build
. Tracked in
_hub_migrations
table.
bash
npx nuxt db generate                  # Generate migrations from schema
npx nuxt db migrate                   # Apply pending migrations
npx nuxt db sql "SELECT * FROM users" # Execute raw SQL
npx nuxt db drop <TABLE>              # Drop a specific table
npx nuxt db drop-all                  # Drop all tables (v0.10+)
npx nuxt db squash                    # Squash migrations into one (v0.10+)
npx nuxt db mark-as-migrated [NAME]   # Mark as migrated without running
迁移会在
npx nuxi dev
npx nuxi build
期间自动应用。迁移记录在
_hub_migrations
表中。

Database Providers

数据库提供商

DialectLocalProduction
sqlite
.data/db/sqlite.db
D1 (Cloudflare), Turso (
TURSO_DATABASE_URL
,
TURSO_AUTH_TOKEN
)
postgresqlPGlitepostgres-js (
DATABASE_URL
), neon-http (v0.10.2+,
DATABASE_URL
)
mysql-mysql2 (
DATABASE_URL
,
MYSQL_URL
)
数据库方言本地环境生产环境
sqlite
.data/db/sqlite.db
D1 (Cloudflare), Turso (
TURSO_DATABASE_URL
,
TURSO_AUTH_TOKEN
)
postgresqlPGlitepostgres-js (
DATABASE_URL
), neon-http (v0.10.2+,
DATABASE_URL
)
mysql-mysql2 (
DATABASE_URL
,
MYSQL_URL
)

KV Storage

KV存储

Key-value storage.
kv
is auto-imported on server-side.
ts
import { kv } from 'hub:kv'

await kv.set('key', { data: 'value' })
await kv.set('key', value, { ttl: 60 }) // TTL in seconds
const value = await kv.get('key')
const exists = await kv.has('key')
await kv.del('key')
const keys = await kv.keys('prefix:')
await kv.clear('prefix:')
Constraints: max value 25 MiB, max key 512 bytes.
键值存储。
kv
会在服务端自动导入。
ts
import { kv } from 'hub:kv'

await kv.set('key', { data: 'value' })
await kv.set('key', value, { ttl: 60 }) // TTL in seconds
const value = await kv.get('key')
const exists = await kv.has('key')
await kv.del('key')
const keys = await kv.keys('prefix:')
await kv.clear('prefix:')
限制:值最大为25 MiB,键最大为512字节。

KV Providers

KV提供商

ProviderPackageEnv Vars
Upstash
@upstash/redis
UPSTASH_REDIS_REST_URL
,
UPSTASH_REDIS_REST_TOKEN
Redis
ioredis
REDIS_URL
Cloudflare KV-
KV
binding in wrangler.jsonc
Deno KV-Auto on Deno Deploy
Vercel-
KV_REST_API_URL
,
KV_REST_API_TOKEN
提供商包名环境变量
Upstash
@upstash/redis
UPSTASH_REDIS_REST_URL
,
UPSTASH_REDIS_REST_TOKEN
Redis
ioredis
REDIS_URL
Cloudflare KV-
KV
binding in wrangler.jsonc
Deno KV-Auto on Deno Deploy
Vercel-
KV_REST_API_URL
,
KV_REST_API_TOKEN

Blob Storage

Blob存储

File storage.
blob
is auto-imported on server-side.
文件存储。
blob
会在服务端自动导入。

Blob API

Blob API

ts
import { blob } from 'hub:blob'

// Upload
const result = await blob.put('path/file.txt', body, {
  contentType: 'text/plain',
  access: 'public', // 'public' | 'private' (v0.10.2+)
  addRandomSuffix: true,
  prefix: 'uploads'
})
// Returns: { pathname, contentType, size, httpEtag, uploadedAt }

// Download
const file = await blob.get('path/file.txt') // Returns Blob or null

// List
const { blobs, cursor, hasMore, folders } = await blob.list({ prefix: 'uploads/', limit: 10, folded: true })

// Serve (with proper headers)
return blob.serve(event, 'path/file.txt')

// Delete
await blob.del('path/file.txt')
await blob.del(['file1.txt', 'file2.txt']) // Multiple

// Metadata only
const meta = await blob.head('path/file.txt')
ts
import { blob } from 'hub:blob'

// Upload
const result = await blob.put('path/file.txt', body, {
  contentType: 'text/plain',
  access: 'public', // 'public' | 'private' (v0.10.2+)
  addRandomSuffix: true,
  prefix: 'uploads'
})
// Returns: { pathname, contentType, size, httpEtag, uploadedAt }

// Download
const file = await blob.get('path/file.txt') // Returns Blob or null

// List
const { blobs, cursor, hasMore, folders } = await blob.list({ prefix: 'uploads/', limit: 10, folded: true })

// Serve (with proper headers)
return blob.serve(event, 'path/file.txt')

// Delete
await blob.del('path/file.txt')
await blob.del(['file1.txt', 'file2.txt']) // Multiple

// Metadata only
const meta = await blob.head('path/file.txt')

Upload Helpers

上传助手

ts
// Server: Validate + upload handler
export default eventHandler(async (event) => {
  return blob.handleUpload(event, {
    formKey: 'files',
    multiple: true,
    ensure: { maxSize: '10MB', types: ['image/png', 'image/jpeg'] },
    put: { addRandomSuffix: true, prefix: 'images' }
  })
})

// Validate before manual upload
ensureBlob(file, { maxSize: '10MB', types: ['image'] })

// Multipart upload for large files (>10MB)
export default eventHandler(async (event) => {
  return blob.handleMultipartUpload(event) // Route: /api/files/multipart/[action]/[...pathname]
})
ts
// Server: Validate + upload handler
export default eventHandler(async (event) => {
  return blob.handleUpload(event, {
    formKey: 'files',
    multiple: true,
    ensure: { maxSize: '10MB', types: ['image/png', 'image/jpeg'] },
    put: { addRandomSuffix: true, prefix: 'images' }
  })
})

// Validate before manual upload
ensureBlob(file, { maxSize: '10MB', types: ['image'] })

// Multipart upload for large files (>10MB)
export default eventHandler(async (event) => {
  return blob.handleMultipartUpload(event) // Route: /api/files/multipart/[action]/[...pathname]
})

Vue Composables

Vue组合式函数

ts
// Simple upload
const upload = useUpload('/api/upload')
const result = await upload(inputElement)

// Multipart with progress
const mpu = useMultipartUpload('/api/files/multipart')
const { completed, progress, abort } = mpu(file)
ts
// Simple upload
const upload = useUpload('/api/upload')
const result = await upload(inputElement)

// Multipart with progress
const mpu = useMultipartUpload('/api/files/multipart')
const { completed, progress, abort } = mpu(file)

Blob Providers

Blob提供商

ProviderPackageConfig
Cloudflare R2-
BLOB
binding in wrangler.jsonc
Vercel Blob
@vercel/blob
BLOB_READ_WRITE_TOKEN
S3
aws4fetch
S3_ACCESS_KEY_ID
,
S3_SECRET_ACCESS_KEY
,
S3_BUCKET
,
S3_REGION
提供商包名配置
Cloudflare R2-
BLOB
binding in wrangler.jsonc
Vercel Blob
@vercel/blob
BLOB_READ_WRITE_TOKEN
S3
aws4fetch
S3_ACCESS_KEY_ID
,
S3_SECRET_ACCESS_KEY
,
S3_BUCKET
,
S3_REGION

Cache

缓存

Response and function caching.
响应和函数缓存。

Route Handler Caching

路由处理器缓存

ts
export default cachedEventHandler((event) => {
  return { data: 'cached', date: new Date().toISOString() }
}, {
  maxAge: 60 * 60, // 1 hour
  getKey: event => event.path
})
ts
export default cachedEventHandler((event) => {
  return { data: 'cached', date: new Date().toISOString() }
}, {
  maxAge: 60 * 60, // 1 hour
  getKey: event => event.path
})

Function Caching

函数缓存

ts
export const getStars = defineCachedFunction(
  async (event: H3Event, repo: string) => {
    const data = await $fetch(`https://api.github.com/repos/${repo}`)
    return data.stargazers_count
  },
  { maxAge: 3600, name: 'ghStars', getKey: (event, repo) => repo }
)
ts
export const getStars = defineCachedFunction(
  async (event: H3Event, repo: string) => {
    const data = await $fetch(`https://api.github.com/repos/${repo}`)
    return data.stargazers_count
  },
  { maxAge: 3600, name: 'ghStars', getKey: (event, repo) => repo }
)

Cache Invalidation

缓存失效

ts
// Remove specific
await useStorage('cache').removeItem('nitro:functions:getStars:repo-name.json')

// Clear by prefix
await useStorage('cache').clear('nitro:handlers')
Cache key pattern:
${group}:${name}:${getKey(...args)}.json
(defaults: group='nitro', name='handlers'|'functions'|'routes')
ts
// Remove specific
await useStorage('cache').removeItem('nitro:functions:getStars:repo-name.json')

// Clear by prefix
await useStorage('cache').clear('nitro:handlers')
缓存键模式:
${group}:${name}:${getKey(...args)}.json
(默认值:group='nitro', name='handlers'|'functions'|'routes')

Deployment

部署

Cloudflare

Cloudflare

NuxtHub auto-generates
wrangler.json
from your hub config - no manual wrangler.jsonc required:
ts
// nuxt.config.ts
export default defineNuxtConfig({
  hub: {
    db: {
      dialect: 'sqlite',
      driver: 'd1',
      connection: { databaseId: '<database-id>' }
    },
    kv: {
      driver: 'cloudflare-kv-binding',
      namespaceId: '<kv-namespace-id>'
    },
    cache: {
      driver: 'cloudflare-kv-binding',
      namespaceId: '<cache-namespace-id>'
    },
    blob: {
      driver: 'cloudflare-r2',
      bucketName: '<bucket-name>'
    }
  }
})
Observability (recommended): Enable logging for production deployments:
jsonc
// wrangler.jsonc (optional)
{
  "observability": {
    "logs": {
      "enabled": true,
      "head_sampling_rate": 1,
      "invocation_logs": true,
      "persist": true
    }
  }
}
Create resources via Cloudflare dashboard or CLI:
bash
npx wrangler d1 create my-db              # Get database-id
npx wrangler kv namespace create KV       # Get kv-namespace-id
npx wrangler kv namespace create CACHE    # Get cache-namespace-id
npx wrangler r2 bucket create my-bucket   # Get bucket-name
Deploy: Create Cloudflare Workers project, link Git repo. Bindings auto-configured at build time.
Environments: Use
CLOUDFLARE_ENV=preview
for preview deployments.
See references/wrangler-templates.md for manual wrangler.jsonc patterns and references/providers.md for all provider configurations.
NuxtHub会根据你的hub配置自动生成
wrangler.json
- 无需手动配置wrangler.jsonc:
ts
// nuxt.config.ts
export default defineNuxtConfig({
  hub: {
    db: {
      dialect: 'sqlite',
      driver: 'd1',
      connection: { databaseId: '<database-id>' }
    },
    kv: {
      driver: 'cloudflare-kv-binding',
      namespaceId: '<kv-namespace-id>'
    },
    cache: {
      driver: 'cloudflare-kv-binding',
      namespaceId: '<cache-namespace-id>'
    },
    blob: {
      driver: 'cloudflare-r2',
      bucketName: '<bucket-name>'
    }
  }
})
可观测性(推荐): 为生产部署启用日志:
jsonc
// wrangler.jsonc (optional)
{
  "observability": {
    "logs": {
      "enabled": true,
      "head_sampling_rate": 1,
      "invocation_logs": true,
      "persist": true
    }
  }
}
通过Cloudflare仪表板或CLI创建资源:
bash
npx wrangler d1 create my-db              # Get database-id
npx wrangler kv namespace create KV       # Get kv-namespace-id
npx wrangler kv namespace create CACHE    # Get cache-namespace-id
npx wrangler r2 bucket create my-bucket   # Get bucket-name
部署:创建Cloudflare Workers项目,关联Git仓库。绑定会在构建时自动配置。
环境: 使用
CLOUDFLARE_ENV=preview
进行预览部署。
有关手动wrangler.jsonc模式,请查看references/wrangler-templates.md,所有提供商配置请查看references/providers.md

Other Providers

其他提供商

See references/providers.md for detailed deployment patterns for:
  • Vercel: Postgres, Turso, Vercel Blob, Vercel KV
  • Netlify: External databases, S3, Upstash Redis
  • Deno Deploy: Deno KV
  • AWS/Self-hosted: S3, RDS, custom configs
有关以下平台的详细部署模式,请查看references/providers.md
  • Vercel: Postgres、Turso、Vercel Blob、Vercel KV
  • Netlify: 外部数据库、S3、Upstash Redis
  • Deno Deploy: Deno KV
  • AWS/自托管: S3、RDS、自定义配置

D1 over HTTP

通过HTTP访问D1

Query D1 from non-Cloudflare hosts:
ts
hub: {
  db: { dialect: 'sqlite', driver: 'd1-http' }
}
Requires:
NUXT_HUB_CLOUDFLARE_ACCOUNT_ID
,
NUXT_HUB_CLOUDFLARE_API_TOKEN
,
NUXT_HUB_CLOUDFLARE_DATABASE_ID
从非Cloudflare主机查询D1:
ts
hub: {
  db: { dialect: 'sqlite', driver: 'd1-http' }
}
需要:
NUXT_HUB_CLOUDFLARE_ACCOUNT_ID
NUXT_HUB_CLOUDFLARE_API_TOKEN
NUXT_HUB_CLOUDFLARE_DATABASE_ID

Build-time Hooks

构建时钩子

ts
// Extend schema
nuxt.hook('hub:db:schema:extend', async ({ dialect, paths }) => {
  paths.push(await resolvePath(`./schema/custom.${dialect}`))
})

// Add migration directories
nuxt.hook('hub:db:migrations:dirs', (dirs) => {
  dirs.push(resolve('./db-migrations'))
})

// Post-migration queries (idempotent)
nuxt.hook('hub:db:queries:paths', (paths, dialect) => {
  paths.push(resolve(`./seed.${dialect}.sql`))
})
ts
// Extend schema
nuxt.hook('hub:db:schema:extend', async ({ dialect, paths }) => {
  paths.push(await resolvePath(`./schema/custom.${dialect}`))
})

// Add migration directories
nuxt.hook('hub:db:migrations:dirs', (dirs) => {
  dirs.push(resolve('./db-migrations'))
})

// Post-migration queries (idempotent)
nuxt.hook('hub:db:queries:paths', (paths, dialect) => {
  paths.push(resolve(`./seed.${dialect}.sql`))
})

Type Sharing

类型共享

ts
// shared/types/db.ts
import type { users } from '~/server/db/schema'

export type User = typeof users.$inferSelect
export type NewUser = typeof users.$inferInsert
ts
// shared/types/db.ts
import type { users } from '~/server/db/schema'

export type User = typeof users.$inferSelect
export type NewUser = typeof users.$inferInsert

WebSocket / Realtime

WebSocket / 实时功能

Enable experimental WebSocket:
ts
// nuxt.config.ts
nitro: { experimental: { websocket: true } }
ts
// server/routes/ws/chat.ts
export default defineWebSocketHandler({
  open(peer) {
    peer.subscribe('chat')
    peer.publish('chat', 'User joined')
  },
  message(peer, message) {
    peer.publish('chat', message.text())
  },
  close(peer) {
    peer.unsubscribe('chat')
  }
})
启用实验性WebSocket:
ts
// nuxt.config.ts
nitro: { experimental: { websocket: true } }
ts
// server/routes/ws/chat.ts
export default defineWebSocketHandler({
  open(peer) {
    peer.subscribe('chat')
    peer.publish('chat', 'User joined')
  },
  message(peer, message) {
    peer.publish('chat', message.text())
  },
  close(peer) {
    peer.unsubscribe('chat')
  }
})

Deprecated (v0.10)

已弃用(v0.10)

Removed Cloudflare-specific features:
  • hubAI()
    -> Use AI SDK with Workers AI Provider
  • hubBrowser()
    -> Puppeteer
  • hubVectorize()
    -> Vectorize
  • NuxtHub Admin -> Sunset Dec 31, 2025
  • npx nuxthub deploy
    -> Use wrangler deploy
移除了Cloudflare特定功能:
  • hubAI()
    -> 使用AI SDK搭配Workers AI Provider
  • hubBrowser()
    -> Puppeteer
  • hubVectorize()
    -> Vectorize
  • NuxtHub Admin -> 将于2025年12月31日停用
  • npx nuxthub deploy
    -> 使用wrangler deploy

Quick Reference

快速参考

FeatureImportAccess
Database
import { db, schema } from 'hub:db'
db.select()
,
db.insert()
, etc.
KV
import { kv } from 'hub:kv'
kv.get()
,
kv.set()
, etc.
Blob
import { blob } from 'hub:blob'
blob.put()
,
blob.get()
, etc.
All are auto-imported on server-side.
功能导入方式使用方式
数据库
import { db, schema } from 'hub:db'
db.select()
,
db.insert()
, etc.
KV
import { kv } from 'hub:kv'
kv.get()
,
kv.set()
, etc.
Blob
import { blob } from 'hub:blob'
blob.put()
,
blob.get()
, etc.
所有模块都会在服务端自动导入。

Resources

资源