What CI/CD is, without the jargon
Continuous integration means every change is checked automatically before it is merged. Continuous delivery means every merged change can be released automatically, the same way each time.
Together they replace "works on my machine" and "who deployed last?" with a process nobody has to remember.
The minimum useful pipeline
For a team of two to ten, four stages cover nearly everything.
1. Checks on every pull request
Before code is reviewed by a person, a machine should have confirmed that it:
- passes linting and formatting
- passes type checking
- passes the automated tests
- builds successfully
In GitHub Actions, that is a short file:
name: CI
on:
pull_request:
push:
branches: [main]
jobs:
check:
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 lint
- run: npx tsc --noEmit
- run: npm test
- run: npm run build
Make these checks required so a failing change cannot be merged. An optional check gets ignored the first time someone is in a hurry.
2. A preview for every pull request
Each pull request gets its own temporary URL with the change deployed. Reviewers, designers and clients look at the real thing rather than a diff. For front-end work this is the single most valuable step.
3. Automatic deploys to staging
Everything merged to the main branch goes to a staging environment that mirrors production. Nobody runs a command. Staging is always the current state of the main branch.
4. A deliberate step to production
Production releases should be a button or a tag — one action, taken by a person, running the same script as staging. And equally important: a rollback that takes one action too. Test it before you need it.
What to add next
Once the basics are steady:
- Database migrations run as part of the deploy, not by hand
- Secrets kept in the platform's secret store, never in the repository
- End-to-end tests for the two or three journeys that must never break — sign-up, checkout, whatever pays the bills
- Error monitoring that tells you about a bad release before a customer does
What you can skip for now
- Multiple approval gates and release committees
- A separate environment per team
- Canary releases and traffic splitting
- Kubernetes — see do you need Kubernetes?
These solve problems of scale. Adding them early costs time and buys nothing.
How to know it is working
Ask two questions. How long from merging a change to it being live? And how afraid are we of deploying on a Friday? A good pipeline makes the first answer "minutes" and the second "not very".
Setting this up is usually a few days of work, and it pays for itself the first time it catches a broken build. It is the foundation of our cloud and DevOps work, and it is in place on every project before the first feature ships.
Working on something like this? See how we approach cloud and DevOps.
