How to Set Up GitHub Actions for CI/CD
Set up GitHub Actions for continuous integration and deployment. Automate tests and deploys on every push with a reusable workflow.
CI/CD in one file
GitHub Actions runs a YAML workflow on your repo’s runners. A single file in
.github/workflows/ can install dependencies, run tests, build, and deploy —
all triggered by a push or pull request.
Step 1 — Create the workflow
.github/workflows/ci.yml:
name: CI
on:
push:
branches: [main]
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm run typecheck
- run: npm test
- run: npm run build
npm ci installs exactly what package-lock.json pins, which is deterministic
in CI (unlike npm install).
Step 2 — Add caching and concurrency
Faster runs and no two deploys racing:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
# ...steps above...
- run: npm ci
- run: npm run build
The cache: npm option on setup-node already restores node_modules between
runs, and cancel-in-progress kills a superseded run the moment a newer push
lands — you never pay twice for the same commit.
Step 3 — Test multiple versions with a matrix
If your library or CLI must work across Node versions, a matrix runs the same job for each combination:
strategy:
matrix:
node-version: [20, 22]
steps:
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
You get one check per version in the PR, each with its own logs — the cheapest way to catch a version-only regression before users do.
Step 5 — Deploy to Cloudflare Pages
Add a deploy job that uses CF_API_TOKEN from repo secrets:
deploy:
needs: build
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CF_API_TOKEN }}
command: pages deploy dist --project-name=your-project
Step 4 — Skip CI when you don’t need it
Include [skip ci] in a commit message and GitHub Actions skips the run
entirely — handy for pure documentation edits that don’t need a full test
cycle. It’s a small habit that keeps the queue focused on code that actually
changes behavior.
Step 6 — Add secrets
GitHub → Settings → Secrets and variables → Actions → New repository secret:
CF_API_TOKEN— a Cloudflare API token with Pages edit scope.
Secrets are encrypted at rest, masked in logs, and never exposed to forks’ pull requests.
Troubleshooting
npm cifails on a missing lockfile — commitpackage-lock.json; CI must not generate it.- Workflow doesn’t run — YAML must live in
.github/workflows/*.ymlon the default branch, and theon:triggers must match. - Secrets empty in a PR from a fork — by design. Secrets are only available in workflows from your own branches.
Summary
Every push to main now typechecks, tests, builds, and deploys automatically.
The workflow is the source of truth for “is this shippable?” — no manual steps.
The same pattern extends further: How to Build and Secure an MCP Server shows how to add a protected API route to a workflow, and Deploy Astro on Cloudflare Pages covers the Pages-side setup this deploys to. Keep the workflow’s Node version aligned with the project’s .nvmrc or engines field so local and CI builds use the same runtime.
Comments
One comment per thread every 30 minutes · edits are unlimited.