CI/CD Deployment
NuxtHub applications deploy through standard CI/CD pipelines. Database migrations require special attention, particularly for Cloudflare D1.
Cloudflare Deployment
Workers Builds
The simplest approach is to use Cloudflare Workers Builds, which automatically deploys your application on every commit.
- Create a Workers project in the Cloudflare dashboard
- Connect your GitHub or GitLab repository
- Configure the build settings:
- Build command:
npm run build - Build output directory:
dist
- Build command:
nuxt.config.ts during the build process. No manual wrangler.jsonc file is required.wrangler.jsonc with named environments, set CLOUDFLARE_ENV as a build-time variable for non-production environments in Workers Builds → Build configuration → Environment variables:CLOUDFLARE_ENV=previewfor preview deploymentsCLOUDFLARE_ENV=stagingfor staging deployments- Leave unset for production (uses default environment)
GitHub Actions
For more control over your deployment process, you can use GitHub Actions:
name: Deploy to Cloudflare
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- name: Install dependencies
run: pnpm install
- name: Build
run: pnpm build
env:
CLOUDFLARE_ENV: ${{ github.ref == 'refs/heads/main' && '' || 'preview' }}
- name: Deploy
run: npx wrangler deploy
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
D1 Migrations in CI/CD
The Problem
Unlike PostgreSQL or MySQL, where build-time migrations work because the database is reachable over the network, Cloudflare D1 presents unique challenges:
- It requires Worker bindings to access the database
- These bindings are only available at runtime
- CI build environments have no database connection
Solution: Pre-Deployment Migration Step
Run migrations before deployment using Wrangler or the NuxtHub CLI.
1. Disable Build-Time Migrations
export default defineNuxtConfig({
hub: {
db: {
dialect: 'sqlite',
driver: 'd1',
connection: { databaseId: '<database-id>' },
applyMigrationsDuringBuild: false
}
}
})
2. Add the Migration Step to Your CI/CD Pipeline
Option A: Using Wrangler (recommended)
Use Wrangler's built-in D1 migrations command. This requires your migrations to follow Wrangler's migration format.
Configure your wrangler.jsonc to use NuxtHub's migration table and output directory:
{
"d1_databases": [{
"binding": "DB",
"database_id": "<database-id>",
"migrations_table": "_hub_migrations",
"migrations_dir": ".output/server/db/migrations/"
}]
}
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- name: Install dependencies
run: pnpm install
# Run migrations BEFORE the build step
- name: Apply D1 Migrations
run: npx wrangler d1 migrations apply <database-name> --remote
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
- name: Build
run: pnpm build
- name: Deploy
run: npx wrangler deploy
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
Option B: Using nuxt db migrate
If you have the D1 HTTP credentials configured, you can use the Nuxt CLI to apply migrations:
- name: Apply D1 Migrations
run: npx nuxt db migrate
env:
NUXT_HUB_CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
NUXT_HUB_CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
NUXT_HUB_CLOUDFLARE_DATABASE_ID: ${{ secrets.CLOUDFLARE_DATABASE_ID }}
nuxt.config.ts has driver: 'd1' or driver: 'd1-http' configured.PostgreSQL / MySQL CI/CD
PostgreSQL and MySQL migrations can run at build time because the database is reachable via a connection string.
- name: Build with migrations
run: pnpm build
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
nuxt build.Running Migrations in a Dedicated Job
For more control over the migration process, you can run migrations in a separate job:
jobs:
migrate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- run: pnpm install
- name: Run migrations
run: npx nuxt db migrate
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
deploy:
needs: migrate
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# ... build and deploy steps
Vercel Deployment
Vercel handles CI/CD automatically when you connect your repository.
Setup
- Import your project in the Vercel dashboard
- Configure environment variables under Project Settings → Environment Variables
- Vercel will deploy automatically on every push
Database Migrations
For Vercel deployments with PostgreSQL or MySQL, migrations run during the build process because Vercel's build environment has network access:
export default defineNuxtConfig({
hub: {
db: {
dialect: 'postgresql',
// Migrations run during build since Vercel's build environment has network access
}
}
})
Environment-Specific Secrets
GitHub Actions
Store your secrets in Repository Settings → Secrets and variables → Actions:
| Secret | Description |
|---|---|
CLOUDFLARE_API_TOKEN | Cloudflare API token with Workers, D1, KV, and R2 permissions |
CLOUDFLARE_ACCOUNT_ID | Your Cloudflare account ID |
CLOUDFLARE_DATABASE_ID | The D1 database ID |
DATABASE_URL | PostgreSQL or MySQL connection string |
Per-Environment Secrets
Use GitHub Environments to separate production and staging secrets:
jobs:
deploy-production:
environment: production
# This job uses secrets from the production environment
deploy-preview:
environment: preview
# This job uses secrets from the preview environment