Loading...
Loading...
Complete CI/CD guide for Cloudflare Workers using GitHub Actions and GitLab CI. Use for automated testing, deployment pipelines, preview environments, secrets management, or encountering deployment failures, workflow errors, environment configuration issues.
npx skill4agent add secondsky/claude-skills workers-ci-cdcloudflare/wrangler-action@v4varssecretsapiTokenapi-token# ❌ 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 }}--dry-run--keep-varsCLOUDFLARE_API_TOKEN.github/workflows/deploy.ymlname: 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: deploygit add .github/workflows/deploy.yml
git commit -m "Add CI/CD pipeline"
git push# Use GitHub Secrets
api-token: ${{ secrets.CLOUDFLARE_API_TOKEN }}# ❌ NEVER hardcode tokens
api-token: "abc123def456..."- run: bun test # ✅ Tests run first
- name: Deploy
uses: cloudflare/wrangler-action@v4
with:
api-token: ${{ secrets.CLOUDFLARE_API_TOKEN }}# ❌ Skipping tests
- name: Deploy
uses: cloudflare/wrangler-action@v4
# No tests!# 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# ❌ Always deploying to production
- run: bunx wrangler deploy- name: Deploy
id: deploy
uses: cloudflare/wrangler-action@v4
- name: Verify Deployment
run: |
curl -f https://your-worker.workers.dev/health || exit 1# ❌ No verification
- name: Deploy
uses: cloudflare/wrangler-action@v4
# Assuming it worked...deploy-production:
environment:
name: production
url: https://your-worker.workers.dev
# Requires manual approval# ❌ Auto-deploy to production without review
deploy-production:
runs-on: ubuntu-latestmain{
"name": "my-worker",
"main": "src/index.ts",
"env": {
"production": {
"name": "my-worker-production",
"vars": {
"ENVIRONMENT": "production"
}
},
"staging": {
"name": "my-worker-staging",
"vars": {
"ENVIRONMENT": "staging"
}
}
}
}# Local development
wrangler secret put DATABASE_URL
# CI/CD (via GitHub Actions)
bunx wrangler secret put DATABASE_URL --env production <<< "${{ secrets.DATABASE_URL }}"- name: Deploy Preview
uses: cloudflare/wrangler-action@v4
with:
api-token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
command: deploy --env preview-${{ github.event.number }}my-worker-preview-42.workers.devname: 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 productionname: 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'
})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: bun test --coverage
- name: Upload Coverage
uses: codecov/codecov-action@v4
with:
files: ./coverage/lcov.infoname: Deploy Production (Manual Approval)
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
environment:
name: production
url: https://my-worker.workers.dev
# Requires manual approval in GitHub Settings
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install
- run: bun test
- name: Deploy
uses: cloudflare/wrangler-action@v4
with:
api-token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
command: deploy --env productionname: Canary Deployment
on:
workflow_dispatch:
inputs:
percentage:
description: 'Traffic percentage to new version'
required: true
default: '10'
jobs:
canary:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install
# Deploy to canary environment
- name: Deploy Canary
uses: cloudflare/wrangler-action@v4
with:
api-token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
command: deploy --env canary
# Configure traffic split via Cloudflare API
# (See references/deployment-strategies.md for full example)feat: add user authentication
fix: resolve rate limiting issue
chore: update dependencies- run: bun run lint
- run: bun run type-check
- run: bun test- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
# Bun automatically caches dependencies- name: Deploy
run: |
if [ "${{ github.ref }}" == "refs/heads/main" ]; then
bunx wrangler deploy --env production
else
bunx wrangler deploy --env staging
fi- name: Notify Slack
if: failure()
uses: slackapi/slack-github-action@v1
with:
payload: |
{"text": "Deployment failed: ${{ github.sha }}"}Error: A valid Cloudflare API token is requiredCLOUDFLARE_API_TOKENapi-token: ${{ secrets.CLOUDFLARE_API_TOKEN }}Error: Not enough permissions to deployError: wrangler.toml not foundwrangler.jsonc- name: Set Secrets
run: |
echo "${{ secrets.DATABASE_URL }}" | bunx wrangler secret put DATABASE_URL --env production- uses: oven-sh/setup-bun@v2
with:
bun-version: latest # Lock version
- run: bun install --frozen-lockfile # Use exact versionscommand: deploy --env preview-${{ github.event.number }}# ❌ WRONG
- run: echo "Token: ${{ secrets.API_TOKEN }}"
# ✅ CORRECT
- run: echo "Deploying..." # No secrets in outputreferences/github-actions.mdreferences/gitlab-ci.mdreferences/deployment-strategies.mdreferences/secrets-management.mdtemplates/github-actions-full.ymltemplates/gitlab-ci-full.ymltemplates/preview-deployment.ymltemplates/rollback-workflow.ymlscripts/verify-deployment.shreferences/secrets-management.md/workers-deploy