Deployment Strategies
Purpose
This skill provides guidance on deploying Cloudflare Workers, managing multiple environments, implementing CI/CD pipelines, and using deployment best practices. Use this skill when setting up deployment workflows, managing staging and production environments, implementing rollback strategies, or integrating with CI/CD systems.
Environment Management
Multi-Environment Configuration
Use wrangler.jsonc environments for staging/production separation:
{
"name": "my-worker",
"main": "src/index.ts",
// Production configuration (default)
"vars": {
"ENVIRONMENT": "production"
},
"kv_namespaces": [
{ "binding": "CACHE", "id": "prod-kv-id" }
],
// Environment-specific overrides
"env": {
"staging": {
"vars": { "ENVIRONMENT": "staging" },
"kv_namespaces": [
{ "binding": "CACHE", "id": "staging-kv-id" }
]
},
"development": {
"vars": { "ENVIRONMENT": "development" },
"kv_namespaces": [
{ "binding": "CACHE", "id": "dev-kv-id" }
]
}
}
}
Deploy to specific environment:
wrangler deploy --env staging wrangler deploy --env production
Best Practices
- •Separate resources: Use different KV namespaces, D1 databases, R2 buckets per environment
- •Environment variables: Use
ENVIRONMENTvar to conditionally enable features - •Secrets per environment:
wrangler secret put API_KEY --env staging - •Test in staging: Always deploy to staging before production
- •Monitor after deploy: Use
wrangler tail --env productionafter deployment
CI/CD Integration
GitHub Actions
.github/workflows/deploy.yml:
name: Deploy Worker
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
name: Deploy
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Deploy to staging
if: github.event_name == 'pull_request'
uses: cloudflare/wrangler-action@v3
with:
apiToken: \${{ secrets.CLOUDFLARE_API_TOKEN }}
command: deploy --env staging
- name: Deploy to production
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
uses: cloudflare/wrangler-action@v3
with:
apiToken: \${{ secrets.CLOUDFLARE_API_TOKEN }}
command: deploy --env production
Setup:
- •Add
CLOUDFLARE_API_TOKENto GitHub Secrets - •Get token from Cloudflare Dashboard → My Profile → API Tokens
- •Create token with "Edit Cloudflare Workers" permissions
GitLab CI
.gitlab-ci.yml:
stages:
- test
- deploy
variables:
NODE_VERSION: "20"
test:
stage: test
image: node:\${NODE_VERSION}
script:
- npm ci
- npm test
deploy_staging:
stage: deploy
image: node:\${NODE_VERSION}
only:
- merge_requests
script:
- npm ci
- npx wrangler deploy --env staging
variables:
CLOUDFLARE_API_TOKEN: \$CLOUDFLARE_API_TOKEN
deploy_production:
stage: deploy
image: node:\${NODE_VERSION}
only:
- main
script:
- npm ci
- npx wrangler deploy --env production
variables:
CLOUDFLARE_API_TOKEN: \$CLOUDFLARE_API_TOKEN
Deployment Workflows
Pre-Deployment Checklist
# 1. Run tests npm test # 2. Build (if applicable) npm run build # 3. Validate configuration wrangler deploy --dry-run --env production # 4. Check migrations (D1) wrangler d1 migrations list DB --remote # 5. Deploy to staging first wrangler deploy --env staging # 6. Test staging curl https://staging.example.com/health # 7. Deploy to production wrangler deploy --env production # 8. Monitor logs wrangler tail --env production
Post-Deployment
# Monitor real-time logs wrangler tail --env production # Check for errors wrangler tail --env production --status error # Verify deployment curl https://production.example.com/health # Check deployment history wrangler deployments list
Rollback Strategies
Quick Rollback
# List recent deployments wrangler deployments list # Rollback to previous deployment wrangler rollback <deployment-id> # Verify rollback wrangler deployments list
Version Pinning
// Add version to response headers
export default {
async fetch(request, env) {
const response = await handleRequest(request, env);
response.headers.set('X-Worker-Version', env.VERSION || 'unknown');
return response;
}
};
Set version in wrangler.jsonc:
{
"vars": {
"VERSION": "1.2.3"
}
}
Canary Deployments
Not natively supported; use percentage-based routing:
export default {
async fetch(request, env) {
const random = Math.random();
// 10% canary traffic
if (random < 0.1) {
return await newVersionHandler(request, env);
}
return await stableVersionHandler(request, env);
}
};
Database Migrations
D1 Migration Workflow
# 1. Create migration wrangler d1 migrations create DB add_users_table # 2. Write SQL in migrations/0001_add_users_table.sql # CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT); # 3. Apply locally wrangler d1 migrations apply DB # 4. Test locally wrangler dev # 5. Apply to staging wrangler d1 migrations apply DB --env staging --remote # 6. Test staging # ... test ... # 7. Apply to production wrangler d1 migrations apply DB --env production --remote # 8. Deploy Worker wrangler deploy --env production
Important: Always apply migrations before deploying Worker code that depends on them.
Secrets Management
Deployment Secrets
# Set secrets per environment wrangler secret put API_KEY --env staging wrangler secret put API_KEY --env production # Different values per environment wrangler secret put DATABASE_URL --env staging # Enter staging database URL wrangler secret put DATABASE_URL --env production # Enter production database URL # List secrets wrangler secret list --env production
Secret Rotation
# 1. Add new secret with different name wrangler secret put API_KEY_NEW --env production # 2. Update Worker code to try new secret first, fall back to old # 3. Deploy updated Worker wrangler deploy --env production # 4. Verify new secret works # 5. Delete old secret wrangler secret delete API_KEY --env production
Monitoring and Observability
Real-Time Monitoring
# All logs wrangler tail --env production # Errors only wrangler tail --env production --status error # Specific method wrangler tail --env production --method POST # Search logs wrangler tail --env production --search "user-id-123"
Health Checks
export default {
async fetch(request, env) {
const url = new URL(request.url);
if (url.pathname === '/health') {
// Check dependencies
try {
await env.DB.prepare('SELECT 1').first();
await env.CACHE.get('health-check');
return new Response(JSON.stringify({
status: 'healthy',
version: env.VERSION,
environment: env.ENVIRONMENT
}), {
headers: { 'Content-Type': 'application/json' }
});
} catch (error) {
return new Response(JSON.stringify({
status: 'unhealthy',
error: error.message
}), {
status: 503,
headers: { 'Content-Type': 'application/json' }
});
}
}
// Regular request handling
return await handleRequest(request, env);
}
};
Best Practices
- •Always test in staging before production
- •Use semantic versioning for releases
- •Automate deployments with CI/CD
- •Monitor after every deployment
- •Have rollback plan ready
- •Apply database migrations before code
- •Use environment-specific resources
- •Keep secrets out of code (use wrangler secret)
- •Tag releases in git for tracking
- •Document deployment process
Troubleshooting
Issue: "Deployment failed - binding not found"
- •Solution: Ensure all bindings (KV, D1, R2) are created and IDs match wrangler.jsonc
Issue: "Migration failed"
- •Solution: Check SQL syntax, ensure migrations run in order, verify database exists
Issue: "Secrets not working after deployment"
- •Solution: Re-set secrets after creating new environment:
wrangler secret put KEY --env ENV
Issue: "Changes not reflecting"
- •Solution: Clear browser cache, check deployment logs, verify correct environment deployed
For the latest deployment documentation, use the cloudflare-docs-specialist agent.