nuxthub-migration

Use when migrating NuxtHub projects or when user mentions NuxtHub Admin sunset, GitHub Actions deployment removal, self-hosting NuxtHub, or upgrading to v0.10/nightly. Covers v0.9.X self-hosting (stable) and v0.10/nightly multi-cloud.

$ 설치

git clone https://github.com/onmax/nuxthub-v1-skill ~/.claude/skills/nuxthub-v1-skill

// tip: Run this command in your terminal to install the skill


name: nuxthub-migration description: Use when migrating NuxtHub projects or when user mentions NuxtHub Admin sunset, GitHub Actions deployment removal, self-hosting NuxtHub, or upgrading to v0.10/nightly. Covers v0.9.X self-hosting (stable) and v0.10/nightly multi-cloud.

NuxtHub Migration

When to Use

Activate this skill when:

  • User mentions NuxtHub Admin deprecation or sunset (Dec 31, 2025)
  • Project uses .github/workflows/nuxthub.yml or NuxtHub GitHub Action
  • User wants to self-host NuxtHub on Cloudflare Workers
  • User asks about migrating to v0.10 or nightly version
  • Project has NUXT_HUB_PROJECT_KEY or NUXT_HUB_PROJECT_DEPLOY_TOKEN env vars

Two-phase migration. Phase 1 is stable and recommended. Phase 2 is multi-cloud.

Phase 1: Self-Hosting (v0.9.X) - RECOMMENDED

Migrate from NuxtHub Admin / GitHub Actions to self-hosted Cloudflare Workers. No code changes required.

1.1 Remove GitHub Action Deployment

Delete .github/workflows/nuxthub.yml or any NuxtHub-specific GitHub Action. Workers CI (step 1.4) replaces this.

Remove deprecated env vars from CI/CD and .env:

  • NUXT_HUB_PROJECT_KEY
  • NUXT_HUB_PROJECT_DEPLOY_TOKEN

Also remove any GitHub Actions secrets related to NuxtHub deployment.

Check and clean up Cloudflare Worker secrets:

npx wrangler secret list --name <worker-name>
npx wrangler secret delete NUXT_HUB_PROJECT_DEPLOY_TOKEN --name <worker-name>

1.2 Get or Create Cloudflare Resources

NuxtHub Admin already created resources in your Cloudflare account. Reuse them to preserve existing data.

List existing resources:

npx wrangler d1 list              # Find existing D1 databases
npx wrangler kv namespace list    # Find existing KV namespaces
npx wrangler r2 bucket list       # Find existing R2 buckets

Look for resources named after your project. Use their IDs in wrangler.jsonc.

Only create new resources if none exist:

# D1 Database (if hub.database: true)
npx wrangler d1 create my-app-db

# KV Namespace (if hub.kv: true)
npx wrangler kv namespace create KV

# KV Namespace for cache (if hub.cache: true)
npx wrangler kv namespace create CACHE

# R2 Bucket (if hub.blob: true)
npx wrangler r2 bucket create my-app-bucket

1.3 Create wrangler.jsonc

Create wrangler.jsonc in project root. See references/wrangler-templates.md for full examples.

Minimal example with database:

{
  "$schema": "node_modules/wrangler/config-schema.json",
  "name": "my-app",
  "main": "dist/server/index.mjs",
  "assets": { "directory": "dist/public" },
  "compatibility_date": "2025-12-01",
  "compatibility_flags": ["nodejs_compat"],
  "d1_databases": [{ "binding": "DB", "database_name": "my-app-db", "database_id": "<from-wrangler-output>" }]
}

Note: Nuxt cloudflare-module preset outputs to dist/, not .output/.

Required binding names:

FeatureBindingType
DatabaseDBD1
KVKVKV Namespace
CacheCACHEKV Namespace
BlobBLOBR2 Bucket

1.4 Set Up Workers Builds CI/CD

Ensure nuxt.config.ts uses the cloudflare_module preset:

nitro: { preset: 'cloudflare_module' }

In Cloudflare Dashboard:

  1. Workers & Pages → Create → Import from Git
  2. Connect GitHub/GitLab repository
  3. Configure build settings (both fields required):
    • Build command: pnpm build (or npm run build)
    • Deploy command: npx wrangler deploy
  4. Add environment variables (e.g., secrets, API keys)

Common mistake: Only setting deploy command. Build must run first to generate .output/.

1.5 Configure Environment Variables (Optional)

For advanced features (blob presigned URLs, cache DevTools, AI):

NUXT_HUB_CLOUDFLARE_ACCOUNT_ID=<account-id>
NUXT_HUB_CLOUDFLARE_API_TOKEN=<token-with-appropriate-permissions>
# Feature-specific (as needed):
NUXT_HUB_CLOUDFLARE_BUCKET_ID=<bucket-id>
NUXT_HUB_CLOUDFLARE_CACHE_NAMESPACE_ID=<namespace-id>

1.6 Test Remote Development

npx nuxt dev --remote

Phase 1 Checklist

  • Delete .github/workflows/nuxthub.yml
  • Remove NUXT_HUB_PROJECT_KEY and NUXT_HUB_PROJECT_DEPLOY_TOKEN env vars
  • Clean up old Worker secrets (wrangler secret list/delete)
  • Get existing or create new Cloudflare resources (D1, KV, R2 as needed)
  • Create wrangler.jsonc with bindings
  • Set nitro.preset: 'cloudflare_module' in nuxt.config.ts
  • Connect repo to Cloudflare Workers Builds
  • Test with npx nuxt dev --remote

No code changes required. Keep hub.database: true, server/database/, hubDatabase(), and @nuxthub/core.


Phase 2: v0.10/Nightly - MULTI-CLOUD

Multi-cloud support (Cloudflare, Vercel, Deno, Netlify). Breaking changes from v0.9.X.

2.1 Update Package

pnpm remove @nuxthub/core
pnpm add @nuxthub/core-nightly

2.2 Update nuxt.config.ts

Before (v0.9.X):

hub: { database: true, kv: true, blob: true, cache: true }

After (v0.10):

hub: { db: 'sqlite', kv: true, blob: true, cache: true }

Key change: database: truedb: '<dialect>' (sqlite | postgresql | mysql)

2.3 Rename Database Directory

mv server/database server/db

Update imports: ~/server/database/~/server/db/

Migrations generated via npx nuxt db generate go to server/db/migrations/{dialect}/.

2.4 Migrate Database API (hubDatabase → Drizzle)

Before:

const db = hubDatabase()
const users = await db.prepare('SELECT * FROM users').all()

After:

import { db, schema } from 'hub:db'
// Note: db and schema are auto-imported on server-side
const users = await db.select().from(schema.users)

2.5 Migrate KV API (hubKV → kv)

Before:

import { hubKV } from '#hub/server'
await hubKV().set('vue', { year: 2014 })
await hubKV().get('vue')
await hubKV().has('vue')
await hubKV().del('vue')
await hubKV().keys('vue:')
await hubKV().clear('vue:')

After:

import { kv } from 'hub:kv'
// Note: kv is auto-imported on server-side
await kv.set('vue', { year: 2014 })
await kv.get('vue')
await kv.has('vue')
await kv.del('vue')
await kv.keys('vue:')
await kv.clear('vue:')

Key change: hubKV() function call → kv direct object. Same methods, different access pattern.

2.6 Migrate Blob API (hubBlob → blob)

Before:

const blob = hubBlob()
await blob.put('file.txt', body, { contentType: 'text/plain' })
await blob.get('file.txt')
await blob.list({ prefix: 'uploads/' })
await blob.del('file.txt')
await blob.serve(event, 'file.txt')

After:

import { blob } from 'hub:blob'
// Note: blob is auto-imported on server-side
await blob.put('file.txt', body, { contentType: 'text/plain' })
await blob.get('file.txt')
await blob.list({ prefix: 'uploads/' })
await blob.del('file.txt')
await blob.serve(event, 'file.txt')

Key change: hubBlob() function call → blob direct object. Same methods, different access pattern.

2.7 New Import Pattern (Summary)

v0.10 uses virtual module imports. All are auto-imported on server-side:

import { db, schema } from 'hub:db'   // Database
import { kv } from 'hub:kv'           // KV Storage
import { blob } from 'hub:blob'       // Blob Storage

2.8 CLI Commands

npx nuxt db generate              # Generate migrations from schema
npx nuxt db migrate               # Apply migrations
npx nuxt db mark-as-migrated [NAME]  # Mark migration as applied without running
npx nuxt db drop <TABLE>          # Drop a table
npx nuxt db sql [QUERY]           # Execute SQL query
npx nuxt db sql < dump.sql        # Execute SQL from file

# All commands support:
--cwd <dir>       # Run in different directory
--dotenv <file>   # Use different .env file
-v, --verbose     # Verbose output

2.9 Provider-Specific Setup (Non-Cloudflare)

Database Providers

PostgreSQL:

pnpm add drizzle-orm drizzle-kit postgres @electric-sql/pglite
  • Uses PGlite locally if no env vars set
  • Uses postgres-js if DATABASE_URL, POSTGRES_URL, or POSTGRESQL_URL set

MySQL:

pnpm add drizzle-orm drizzle-kit mysql2
  • Requires DATABASE_URL or MYSQL_URL env var

SQLite (Turso):

pnpm add drizzle-orm drizzle-kit @libsql/client
  • Uses libsql locally at .data/db/sqlite.db
  • Uses Turso if TURSO_DATABASE_URL and TURSO_AUTH_TOKEN set

KV Providers

ProviderPackageEnv Vars
Upstash@upstash/redisUPSTASH_REDIS_REST_URL, UPSTASH_REDIS_REST_TOKEN
RedisioredisREDIS_URL
Cloudflare KV-KV binding in wrangler.jsonc
Deno KV-Auto on Deno Deploy
Vercel-KV_REST_API_URL, KV_REST_API_TOKEN

Blob Providers

ProviderPackageConfig
Vercel Blob@vercel/blobDashboard setup
Cloudflare R2-BLOB binding in wrangler.jsonc
S3aws4fetchS3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, S3_BUCKET, S3_REGION
Netlify Blobs@netlify/blobsNETLIFY_BLOB_STORE_NAME

2.10 Database Hooks (For Nuxt Modules)

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

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

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

2.11 Schema Files

Schema can be in multiple locations:

  • server/db/schema.ts
  • server/db/schema.{dialect}.ts
  • server/db/schema/*.ts
  • server/db/schema/*.{dialect}.ts

Generated schema at .nuxt/hub/db/schema.mjs.

Deprecated Features (v0.10)

Cloudflare-specific features removed:

  • hubAI() - Use AI SDK with Workers AI Provider
  • hubBrowser() - Puppeteer
  • hubVectorize() - Vectorize
  • hubAutoRAG() - AutoRAG

Phase 2 Checklist

  • Complete Phase 1 first
  • Replace @nuxthub/core with @nuxthub/core-nightly
  • Change hub.database: true to hub.db: 'sqlite' (or other dialect)
  • Rename server/database/ to server/db/
  • Update imports from ~/server/database/ to ~/server/db/
  • Migrate hubDatabase()db from hub:db
  • Migrate hubKV()kv from hub:kv
  • Migrate hubBlob()blob from hub:blob
  • Update table references: tables.Xschema.X
  • Run npx nuxt db generate to generate migrations
  • Test all database, KV, and blob operations

Quick Reference

Aspectv0.9.X (Phase 1)v0.10/Nightly (Phase 2)
Package@nuxthub/core@nuxthub/core-nightly
Database confighub.database: truehub.db: 'sqlite'
Directoryserver/database/server/db/
DB accesshubDatabase()db from hub:db
Schema accessN/Aschema from hub:db
KV accesshubKV()kv from hub:kv
Blob accesshubBlob()blob from hub:blob
MigrationsManual SQLnpx nuxt db generate
Cloud supportCloudflare onlyMulti-cloud

Resources