Skip to content

Production Deployment

Production deployment is where everything counts. Every migration affects real users and real data. This guide walks you through deploying to production safely and confidently.

The Production Mindset

flowchart LR
  A["Staging ✅"] --> B["Review Changes"]
  B --> C["Backup Data"]
  C --> D["Apply Migrations"]
  D --> E["Deploy Code"]
  E --> F["Verify & Monitor"]

Production deployments require extra diligence:

  • Test everything in staging first - No exceptions
  • Have a rollback plan - Know how to recover before you deploy
  • Deploy during low-traffic periods - Minimize user impact
  • Monitor after deployment - Catch issues early

Prerequisites

Before deploying to production, ensure:

  1. Staging deployment successful - All changes validated (see Staging Deployment)
  2. Migrations tested - Applied and verified in staging
  3. Team notified - Stakeholders aware of the deployment
  4. Rollback plan ready - Know exactly what to do if something fails

Step 1: Create the Production Database

Create your production D1 database on Cloudflare.

Creating the Database

Terminal
pnpm wrangler d1 create d1-migration-mastery-production

Expected output:

✅ Successfully created DB 'd1-migration-mastery-production' in region WNAM
Created your new D1 database.
[[d1_databases]]
binding = "DB"
database_name = "d1-migration-mastery-production"
database_id = "a1b2c3d4-e5f6-7890-abcd-ef1234567890"

Adding to wrangler.toml

Add the production database configuration:

wrangler.toml
# Production Environment
[env.production]
name = "d1-migration-mastery-production"
[[env.production.d1_databases]]
binding = "DB"
database_name = "d1-migration-mastery-production"
database_id = "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
migrations_dir = "migrations"

Verifying the Database

Confirm your production database exists:

Terminal
pnpm wrangler d1 list

Expected output:

┌────────────────────────────────────┬──────────────────────────────────────┬────────┐
│ Name │ ID │ Region │
├────────────────────────────────────┼──────────────────────────────────────┼────────┤
│ d1-migration-mastery-staging │ f1e2d3c4-b5a6-0987-fedc-ba0987654321 │ WNAM │
├────────────────────────────────────┼──────────────────────────────────────┼────────┤
│ d1-migration-mastery-production │ a1b2c3d4-e5f6-7890-abcd-ef1234567890 │ WNAM │
└────────────────────────────────────┴──────────────────────────────────────┴────────┘

Step 2: Safe Migration Practices

Production migrations require careful planning and execution.

Pre-Migration Checklist

Before running any production migration:

flowchart TD
  A["Pre-Migration Checklist"] --> B["✅ Tested in staging?"]
  B --> C["✅ Reviewed migration SQL?"]
  C --> D["✅ Backup strategy ready?"]
  D --> E["✅ Rollback plan documented?"]
  E --> F["✅ Low-traffic period?"]
  F --> G["✅ Team notified?"]
  G --> H["Proceed with Migration"]

CheckDescription
Tested in stagingMigration ran successfully without errors
Reviewed SQLVerified the generated SQL does what you expect
Backup readyKnow how to restore if needed
Rollback documentedWritten steps to undo changes
Low trafficDeploying during off-peak hours
Team notifiedEveryone knows deployment is happening

Reviewing Migration Files

Always review what will be executed:

Terminal
# List pending migrations
pnpm wrangler d1 migrations list DB --remote --env production

Expected output (before applying):

Migrations:
┌─────────────────────────────────────┬────────────────────┐
│ name │ status │
├─────────────────────────────────────┼────────────────────┤
│ 0000_initial.sql │ ✅ Applied │
├─────────────────────────────────────┼────────────────────┤
│ 0001_add_user_profile.sql │ ✅ Applied │
├─────────────────────────────────────┼────────────────────┤
│ 0002_add_posts.sql │ ⏳ Pending │
└─────────────────────────────────────┴────────────────────┘

Reading the Migration SQL

Read the actual SQL before applying:

Terminal
cat migrations/0002_add_posts.sql

Look for:

  • Destructive operations - DROP TABLE, DROP COLUMN
  • Data modifications - UPDATE, DELETE
  • Schema changes - Understand exactly what’s changing

Applying Production Migrations

Once verified, apply the migration:

Terminal
pnpm wrangler d1 migrations apply DB --remote --env production

Expected output:

Migrations to be applied:
┌─────────────────────────────────────┐
│ name │
├─────────────────────────────────────┤
│ 0002_add_posts.sql │
└─────────────────────────────────────┘
✔ About to apply 1 migration(s)
Your database may not be available to serve requests during the migration, continue? … yes
🌀 Executing on remote database DB (a1b2c3d4-e5f6-7890-abcd-ef1234567890):
Applying migration: 0002_add_posts.sql
Running query 1/2: CREATE TABLE `posts`...
✔ Query 1/2 succeeded
Running query 2/2: CREATE INDEX...
✔ Query 2/2 succeeded
✔ Applied 0002_add_posts.sql
✅ 1 migration(s) applied successfully

Step 3: Deploy the Application

With migrations applied, deploy your Worker code.

Deploying to Production

Terminal
pnpm wrangler deploy --env production

Expected output:

⛅️ wrangler 3.x.x
-------------------
Your worker has access to the following bindings:
- D1 Databases:
- DB: d1-migration-mastery-production (a1b2c3d4-e5f6-7890-abcd-ef1234567890)
Total Upload: 150.23 KiB / gzip: 35.67 KiB
Worker Startup Time: 15 ms
Uploaded d1-migration-mastery-production (2.50 sec)
Published d1-migration-mastery-production (0.35 sec)
https://d1-migration-mastery-production.<your-subdomain>.workers.dev
Current Deployment ID: prod123-abc456-def789
Current Version ID: version-abc123-xyz

Verifying Deployment

Test that the deployment was successful:

Terminal
# Quick health check
curl https://d1-migration-mastery-production.<your-subdomain>.workers.dev/health
# Or test an API endpoint
curl https://d1-migration-mastery-production.<your-subdomain>.workers.dev/users

Step 4: Rollback Strategies

Things can go wrong. Have a plan ready before you need it.

flowchart TD
  A["Issue Detected"] --> B{What failed?}

  B -->|"Code bug"| C["Rollback Code"]
  B -->|"Migration broke data"| D["Restore from Backup"]
  B -->|"Both"| E["Rollback Code + Restore Data"]

  C --> F["Deploy previous version"]
  D --> G["Use D1 Time Travel"]
  E --> H["Coordinate both"]

  F --> I["Verify fix"]
  G --> I
  H --> I

Strategy 1: Rollback Code Only

If the issue is in your Worker code (not the migration):

Terminal
# List recent deployments
pnpm wrangler deployments list --env production
# Rollback to previous version
pnpm wrangler rollback --env production

Expected output:

⛅️ wrangler 3.x.x
-------------------
Successfully rolled back to deployment prod122-abc456-def788
Current Version ID: version-abc122-xyz

Strategy 2: Restore Database from Backup

D1 supports point-in-time recovery using Time Travel:

Terminal
# List available bookmarks (restore points)
pnpm wrangler d1 time-travel info DB --env production
# Restore to a specific point in time (within last 30 days)
pnpm wrangler d1 time-travel restore DB --env production --timestamp "2024-01-15T10:00:00Z"

Strategy 3: Forward-Fix Migration

Sometimes the best approach is a new migration that fixes the issue:

Terminal
# Generate a fix migration
pnpm drizzle-kit generate --name fix_column_issue
# Apply the fix
pnpm wrangler d1 migrations apply DB --remote --env production

Strategy 4: Manual SQL Fix

For urgent issues, execute SQL directly:

Terminal
# Execute a fix directly (use with caution)
pnpm wrangler d1 execute DB --remote --env production \
--command "UPDATE users SET status = 'active' WHERE status IS NULL"

When to Use Each Strategy

ScenarioStrategy
Code bug, data is fineRollback code
Migration corrupted dataRestore from backup
Missing column or indexForward-fix migration
Simple data correctionManual SQL fix
Major outageRollback code + restore data

Production Deployment Checklist

Use this checklist for every production deployment:

Before Deployment

CheckStatus
Changes tested in staging
Migration SQL reviewed
Rollback plan documented
Team notified of deployment
Low-traffic period selected
Monitoring dashboards open

During Deployment

StepCommandStatus
Check pending migrationspnpm wrangler d1 migrations list DB --remote --env production
Apply migrationspnpm wrangler d1 migrations apply DB --remote --env production
Deploy Workerpnpm wrangler deploy --env production
Verify deploymentVisit production URL

After Deployment

CheckStatus
API endpoints responding
No errors in logs
Database queries working
Performance acceptable
Team notified of completion

Post-Deployment Monitoring

After deployment, actively monitor for issues.

Watching Logs

Stream real-time logs from production:

Terminal
pnpm wrangler tail --env production

Expected output:

⬣ Listening for logs...
[2024-01-15 10:30:45] GET /users 200 OK (45ms)
[2024-01-15 10:30:46] POST /users 201 Created (120ms)
[2024-01-15 10:30:47] GET /users/1 200 OK (35ms)

Key Metrics to Watch

Monitor these in the Cloudflare dashboard:

MetricHealthy RangeAction if Unhealthy
Error rate< 1%Check logs, rollback if needed
Response time< 200msInvestigate slow queries
Request volumeNormal for time of dayVerify no traffic drop
CPU time< 10ms averageOptimize heavy operations

Checking Database Health

Verify database is performing well:

Terminal
# Check table sizes
pnpm wrangler d1 execute DB --remote --env production \
--command "SELECT name, COUNT(*) as rows FROM sqlite_master WHERE type='table'"
# Verify recent data
pnpm wrangler d1 execute DB --remote --env production \
--command "SELECT COUNT(*) FROM users WHERE createdAt > datetime('now', '-1 hour')"

Quick Reference

TaskCommand
Create production databasepnpm wrangler d1 create <name>
List migrationspnpm wrangler d1 migrations list DB --remote --env production
Apply migrationspnpm wrangler d1 migrations apply DB --remote --env production
Deploy to productionpnpm wrangler deploy --env production
View production logspnpm wrangler tail --env production
Rollback deploymentpnpm wrangler rollback --env production
Execute SQLpnpm wrangler d1 execute DB --remote --env production --command "..."

Summary

Safe production deployment follows these principles:

  1. Always test in staging first - No shortcuts
  2. Review migrations before applying - Know exactly what will run
  3. Have a rollback plan - Document it before you deploy
  4. Monitor after deployment - Catch issues before users report them
  5. Deploy during low-traffic periods - Minimize user impact

With these practices, you can deploy to production confidently and recover quickly if issues arise.