CI/CD stands for Continuous Integration and Continuous Deployment. It means automating the boring stuff β testing, building, and deploying your code β so it happens every time you push, without you thinking about it.
The problem CI/CD solves
Without CI/CD:
- You write code
- You forget to run tests
- You merge broken code
- Someone deploys on Friday at 5pm
- The site goes down
- Everyone panics
With CI/CD:
- You push code
- Tests run automatically
- If tests pass, code gets deployed automatically
- If tests fail, the merge is blocked
- Nobody deploys broken code
CI β Continuous Integration
Every time someone pushes code or opens a pull request, a server automatically:
- Checks out the code
- Installs dependencies
- Runs the linter
- Runs the tests
- Builds the project
If any step fails, the team gets notified and the PR canβt be merged.
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npm run lint
- run: npm test
- run: npm run build
Thatβs a real CI pipeline. It runs on every push and PR. If npm test fails, the whole pipeline fails and you see a red β on the PR.
CD β Continuous Deployment
After CI passes, CD automatically deploys the code to production (or staging).
# Simplified: deploy to Vercel after tests pass
jobs:
test:
# ... (same as above)
deploy:
needs: test # Only runs if test job passes
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- run: npx vercel --prod --token=${{ secrets.VERCEL_TOKEN }}
Push to main β tests pass β deployed to production. No manual steps.
Continuous Deployment vs. Continuous Delivery:
- Continuous Deployment: auto-deploys to production (fully automated)
- Continuous Delivery: auto-deploys to staging, requires manual approval for production
Most teams start with Continuous Delivery and move to Continuous Deployment once they trust their test suite.
CI/CD tools
| Tool | Type | Best for |
|---|---|---|
| GitHub Actions | Built into GitHub | Most projects |
| GitLab CI | Built into GitLab | GitLab users |
| Jenkins | Self-hosted | Enterprise, complex pipelines |
| CircleCI | Cloud | Fast builds |
| Vercel / Netlify | Cloud | Frontend auto-deploy |
GitHub Actions is the most popular for open source and small teams. Itβs free for public repos and has generous free minutes for private repos.
See: GitHub Actions cheat sheet
What a typical pipeline looks like
Push code β Lint β Test β Build β Deploy to staging β Deploy to production
β
(manual approval)
For a simple project:
Push to main β Install β Lint β Test β Build β Deploy
For a more mature project:
Open PR β Lint β Unit tests β Integration tests β Preview deploy
Merge PR β All tests β Build β Deploy to staging β Smoke tests β Deploy to production
Setting up CI/CD (5-minute version)
If youβre on GitHub with a Node.js project, create this file:
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
- run: npm test
Push it. Thatβs it. You now have CI.
If youβre using Vercel or Netlify for hosting, you already have CD β they auto-deploy on every push to main.
Why it matters
- Catches bugs before they reach production. Tests run on every push, not just when someone remembers.
- Faster feedback. You know within minutes if your code broke something.
- Consistent deployments. No more βI deployed from my laptop and forgot to build first.β
- Team confidence. Everyone can merge knowing the pipeline will catch problems.
The initial setup takes 10 minutes. The time it saves over a projectβs lifetime is measured in weeks.