// This skill should be used when the user asks about "deployment", "CI/CD", "continuous integration", "GitHub Actions", "GitLab CI", "environments", "staging", "production", "rollback", "versioning", "gradual rollout", "canary deployment", "blue-green deployment", or discusses deploying Workers, managing multiple environments, or setting up automated deployment pipelines.
| name | Deployment Strategies |
| description | This skill should be used when the user asks about "deployment", "CI/CD", "continuous integration", "GitHub Actions", "GitLab CI", "environments", "staging", "production", "rollback", "versioning", "gradual rollout", "canary deployment", "blue-green deployment", or discusses deploying Workers, managing multiple environments, or setting up automated deployment pipelines. |
| version | 0.1.0 |
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.
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
ENVIRONMENT var to conditionally enable featureswrangler secret put API_KEY --env stagingwrangler tail --env production after deployment.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:
CLOUDFLARE_API_TOKEN to GitHub Secrets.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
# 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
# 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
# List recent deployments
wrangler deployments list
# Rollback to previous deployment
wrangler rollback <deployment-id>
# Verify rollback
wrangler deployments list
// 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"
}
}
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);
}
};
# 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.
# 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
# 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
# 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"
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);
}
};
Issue: "Deployment failed - binding not found"
Issue: "Migration failed"
Issue: "Secrets not working after deployment"
wrangler secret put KEY --env ENVIssue: "Changes not reflecting"
For the latest deployment documentation, use the cloudflare-docs-specialist agent.