DevOps CI/CD

Zero to Production:
CI/CD for Cloudflare Workers

GitHub Actions workflows, Wrangler deployments, environment management, and rollback strategies for 28 production workers.

๐Ÿ“– 14 min read January 24, 2026

Deploying one Worker is easy. Deploying 28 Workers across three environments with zero downtime, automatic rollbacks, and proper secret management? That requires a real CI/CD pipeline.

This is the exact deployment infrastructure running in productionโ€”from git push to global edge deployment in under 90 seconds.

The Pipeline

Deployment Pipeline (Push to Production)
๐Ÿ“
Commit
0s
โ†’
๐Ÿ”
Lint/Type
15s
โ†’
๐Ÿงช
Test
30s
โ†’
๐Ÿ“ฆ
Build
45s
โ†’
๐Ÿš€
Deploy
90s

GitHub Actions Workflow

The main deployment workflow handles linting, testing, and deploying to the correct environment based on branch:

.github/workflows/deploy.yml
name: Deploy Workers on: push: branches: [main, staging, develop] pull_request: branches: [main] env: NODE_VERSION: '20' jobs: lint-and-test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Node uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} cache: 'npm' - run: npm ci - run: npm run lint - run: npm run typecheck - run: npm run test deploy: needs: lint-and-test if: github.event_name == 'push' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Node uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} cache: 'npm' - run: npm ci - name: Determine Environment id: env run: | if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then echo "environment=production" >> $GITHUB_OUTPUT elif [[ "${{ github.ref }}" == "refs/heads/staging" ]]; then echo "environment=staging" >> $GITHUB_OUTPUT else echo "environment=development" >> $GITHUB_OUTPUT fi - name: Deploy to Cloudflare uses: cloudflare/wrangler-action@v3 with: apiToken: ${{ secrets.CF_API_TOKEN }} accountId: ${{ secrets.CF_ACCOUNT_ID }} command: deploy --env ${{ steps.env.outputs.environment }}

Environment Configuration

Each environment has its own configuration in wrangler.toml:

wrangler.toml
name = "api-gateway" main = "src/index.ts" compatibility_date = "2024-01-01" # Shared bindings [[kv_namespaces]] binding = "CACHE" # Development [env.development] name = "api-gateway-dev" vars = { ENVIRONMENT = "development", LOG_LEVEL = "debug" } [[env.development.kv_namespaces]] binding = "CACHE" id = "abc123-dev" # Staging [env.staging] name = "api-gateway-staging" vars = { ENVIRONMENT = "staging", LOG_LEVEL = "info" } [[env.staging.kv_namespaces]] binding = "CACHE" id = "abc123-staging" # Production [env.production] name = "api-gateway" vars = { ENVIRONMENT = "production", LOG_LEVEL = "warn" } routes = [{ pattern = "api.proptechusa.ai/*", zone_name = "proptechusa.ai" }] [[env.production.kv_namespaces]] binding = "CACHE" id = "abc123-prod"

Secrets Management

Never commit secrets. Use Wrangler to set them per environment:

scripts/setup-secrets.sh
#!/bin/bash # Set secrets for each environment for env in development staging production; do echo "Setting secrets for $env..." wrangler secret put ANTHROPIC_API_KEY --env $env wrangler secret put SLACK_WEBHOOK_URL --env $env wrangler secret put DATABASE_URL --env $env echo "โœ“ $env secrets configured" done
Secret Dev Staging Production
ANTHROPIC_API_KEY Test key Test key Production key
SLACK_WEBHOOK_URL #dev-alerts #staging-alerts #production-alerts
DATABASE_URL D1 dev DB D1 staging DB D1 prod DB

Multi-Worker Deployments

With 28 workers, we use a matrix strategy to deploy in parallel:

.github/workflows/deploy-all.yml
jobs: deploy-workers: runs-on: ubuntu-latest strategy: matrix: worker: - api-gateway - lead-processor - valuation-engine - notify-slack - notify-email - ai-chatbot - analytics - webhook-receiver # ... 20 more workers fail-fast: false # Don't stop on single failure steps: - uses: actions/checkout@v4 - name: Deploy ${{ matrix.worker }} working-directory: workers/${{ matrix.worker }} run: npx wrangler deploy --env production env: CLOUDFLARE_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
Parallel Deployment
Matrix deployments run in parallel. 28 workers deploy in ~90 seconds total instead of 28 ร— 30s = 14 minutes sequentially. The fail-fast: false ensures one failing worker doesn't block others.

Rollback Strategy

Every deployment needs a rollback plan. Cloudflare keeps previous versions:

scripts/rollback.sh
#!/bin/bash # Rollback to previous version WORKER_NAME=$1 VERSION=$2 # Optional: specific version, defaults to previous if [ -z "$VERSION" ]; then # Get previous deployment VERSION=$(wrangler deployments list --name $WORKER_NAME | head -2 | tail -1 | awk '{print $1}') fi echo "Rolling back $WORKER_NAME to $VERSION..." wrangler rollback --name $WORKER_NAME --version $VERSION # Notify Slack curl -X POST $SLACK_WEBHOOK -d "{\"text\":\"โš ๏ธ Rollback: $WORKER_NAME โ†’ $VERSION\"}"

Health Checks

Post-deployment verification ensures workers are healthy:

.github/workflows/health-check.yml
post-deploy-check: needs: deploy runs-on: ubuntu-latest steps: - name: Wait for propagation run: sleep 10 - name: Health check run: | response=$(curl -s -o /dev/null -w "%{http_code}" https://api.proptechusa.ai/health) if [ "$response" != "200" ]; then echo "Health check failed with status $response" exit 1 fi echo "โœ“ Health check passed" - name: Smoke test run: | # Test critical endpoints curl -f https://api.proptechusa.ai/v1/status curl -f https://api.proptechusa.ai/v1/valuation/health echo "โœ“ Smoke tests passed" - name: Notify success if: success() run: | curl -X POST ${{ secrets.SLACK_WEBHOOK }} \ -d '{"text":"โœ… Deployment successful: ${{ github.sha }}"}' - name: Auto-rollback on failure if: failure() run: | ./scripts/rollback.sh api-gateway curl -X POST ${{ secrets.SLACK_WEBHOOK }} \ -d '{"text":"๐Ÿšจ Auto-rollback triggered: ${{ github.sha }}"}'

Production Checklist

  • Branch protection on main (require PR reviews)
  • Secrets stored in GitHub Secrets, never committed
  • Separate KV/D1/R2 namespaces per environment
  • Health checks after every deployment
  • Automatic rollback on failure
  • Slack notifications for deploys and failures
  • Matrix deployments for parallel worker updates
  • Deployment logs retained for debugging

A good CI/CD pipeline isn't about automationโ€”it's about confidence. Every push should either succeed completely or fail safely with automatic recovery.

Related Articles

28 Cloudflare Workers: Real-Time SaaS Architecture
Read more โ†’
Building a Service Mesh on Cloudflare Workers
Read more โ†’
The Real Cost of Serverless: 12-Month Analysis
Read more โ†’

Need CI/CD Setup for Your Workers?

We build production deployment pipelines that scale.

โ†’ Get Started
๐ŸŒ™