Cloudflare Workers CI/CD
Status: ✅ Production Ready | Last Verified: 2025-01-27 GitHub Actions: v4 | GitLab CI: Latest | Wrangler: 4.50.0
Table of Contents
- [What Is Workers CI/CD?](#what-is-workers-cicd)
- [New in 2025](#new-in-2025)
- [Quick Start (10 Minutes)](#quick-start-10-minutes)
- [Critical Rules](#critical-rules)
- [Core Concepts](#core-concepts)
- [Top 5 Use Cases](#top-5-use-cases)
- [Best Practices](#best-practices)
- [Top 7 Errors Prevented](#top-7-errors-prevented)
- [When to Load References](#when-to-load-references)
What Is Workers CI/CD?
Automated testing and deployment of Cloudflare Workers using GitHub Actions or GitLab CI. Enables running tests on every commit, deploying to preview/staging/production environments automatically, managing secrets securely, and implementing deployment gates for safe releases.
Key capabilities: Automated testing, multi-environment deployments, preview URLs per PR, secrets management, deployment verification, automatic rollbacks.
New in 2025
GitHub Actions Updates (January 2025):
- NEW:
cloudflare/wrangler-action@v4(improved caching, faster deployments) - IMPROVED: Secrets support with
varsandsecretsparameters - ADDED: Built-in preview environment cleanup
- BREAKING:
apiTokenrenamed toapi-token(kebab-case)
Migration from v3:
# ❌ OLD (v3)
- uses: cloudflare/wrangler-action@3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
# ✅ NEW (v4)
- uses: cloudflare/wrangler-action@v4
with:
api-token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
Wrangler 4.50.0 (January 2025):
- NEW:
--dry-runflag for deployment validation - IMPROVED: Faster deployments with parallel uploads
- ADDED:
--keep-varsto preserve environment variables
Quick Start (10 Minutes)
GitHub Actions Setup
1. Create Cloudflare API Token
Go to: https://dash.cloudflare.com/profile/api-tokens
Create token with permissions:
- Account.Cloudflare Workers Scripts - Edit
- Account.Cloudflare Pages - Edit (if using Pages)
2. Add Secret to GitHub
Repository → Settings → Secrets → Actions → New repository secret:
- Name:
CLOUDFLARE_API_TOKEN - Value: [paste token]
3. Create .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
name: Deploy to Cloudflare Workers
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- run: bun install
- run: bun test
- name: Deploy
uses: cloudflare/wrangler-action@v4
with:
api-token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
command: deploy
4. Push and Verify
git add .github/workflows/deploy.yml
git commit -m "Add CI/CD pipeline"
git push
Check Actions tab on GitHub to see deployment progress.
Critical Rules
1. Never Commit Secrets to Git
✅ CORRECT:
# Use GitHub Secrets
api-token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
❌ WRONG:
# ❌ NEVER hardcode tokens
api-token: "abc123def456..."
Why: Exposed tokens allow anyone to deploy to your account.
2. Always Run Tests Before Deploy
✅ CORRECT:
- run: bun test # ✅ Tests run first
- name: Deploy
uses: cloudflare/wrangler-action@v4
with:
api-token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
❌ WRONG:
# ❌ Skipping tests
- name: Deploy
uses: cloudflare/wrangler-action@v4
# No tests!
Why: Broken code shouldn't reach production.
3. Use Different Environments
✅ CORRECT:
# Production (main branch)
- name: Deploy to Production
if: github.ref == 'refs/heads/main'
run: bunx wrangler deploy --env production
# Staging (other branches)
- name: Deploy to Staging
if: github.ref != 'refs/heads/main'
run: bunx wrangler deploy --env staging
❌ WRONG:
# ❌ Always deploying to production
- run: bunx wrangler deploy
Why: Test changes in staging before production.
4. Verify Deployment Success
✅ CORRECT:
- name: Deploy
id: deploy
uses: cloudflare/wrangler-action@v4
- name: Verify Deployment
run: |
curl -f https://your-worker.workers.dev/health || exit 1
❌ WRONG:
# ❌ No verification
- name: Deploy
uses: cloudflare/wrangler-action@v4
# Assuming it worked...
Why: Deployments can fail silently (DNS issues, binding errors).
5. Use Deployment Gates for Production
✅ CORRECT:
deploy-production:
environment:
name: production
url: https://your-worker.workers.dev
# Requires manual approval
❌ WRONG:
# ❌ Auto-deploy to production without review
deploy-production:
runs-on: ubuntu-latest
Why: Human review catches issues automation misses.
Core Concepts
Multi-Environment Strategy
Recommended setup:
- Production:
mainbranch → production environment - Staging: Pull requests → staging environment
- Preview: Each PR → unique preview URL
wrangler.jsonc:
{
"name": "my-worker",
"main": "src/index.ts",
"env": {
"production": {
"name": "my-worker-production",
"vars": {
"ENVIRONMENT": "production"
}
},
"staging": {
"name": "my-worker-staging",
"vars": {
"ENVIRONMENT": "staging"
}
}
}
}
Secrets Management
Types of configuration:
- Public variables (wrangler.jsonc) - Non-sensitive config
- Secrets (wrangler secret) - API keys, tokens
- CI variables (GitHub Secrets) - Deployment credentials
Setting secrets:
# Local development
wrangler secret put DATABASE_URL
# CI/CD (via GitHub Actions)
bunx wrangler secret put DATABASE_URL --env production <<< "${{ secrets.DATABASE_URL }}"
Preview Deployments
Automatically deploy each PR to a unique URL for testing:
- name: Deploy Preview
uses: cloudflare/wrangler-action@v4
with:
api-token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
command: deploy --env preview-${{ github.event.number }}
Each PR gets URL like: my-worker-preview-42.workers.dev
Top 5 Use Cases
1. Deploy on Push to Main
name: Deploy Production
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install
- run: bun test
- run: bun run build
- name: Deploy to Production
uses: cloudflare/wrangler-action@v4
with:
api-token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
command: deploy --env production
2. Preview Deployments for PRs
name: Preview
on:
pull_request:
branches: [main]
jobs:
preview:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install
- run: bun test
- name: Deploy Preview
id: deploy
uses: cloudflare/wrangler-action@v4
with:
api-token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
command: deploy --env preview-${{ github.event.number }}
- name: Comment PR
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '✅ Preview deployed to: https://my-worker-preview-${{ github.event.number }}.workers.dev'
})
3. Run Tests on Every Commit
name: Test
on:
push:
branches: ['**']
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install
- run: b