CI/CD is the automated pipeline that takes our code from a git push to running in production, with as little manual fiddling as possible. In simple language — it’s the assembly line that builds, tests, and ships our code so humans don’t do it by hand (and don’t forget a step at 5pm on a Friday).
The why: manual builds and deploys are slow, inconsistent, and error-prone. Automating them means changes land fast, in small batches, tested the same way every time — so bugs get caught early and a bad deploy is a quick rollback instead of a crisis.
CI vs CD — they’re two different things
The acronym smushes two ideas together. Interviewers like us to split them cleanly.
- CI (Continuous Integration) — developers merge their work into the shared main branch frequently (many times a day), and every merge automatically triggers a build + test run. The goal: catch integration problems now, while the change is small, instead of during a giant painful merge later.
- CD — has two flavors people conflate:
- Continuous Delivery — every change that passes CI is automatically prepared and made deployable; a human clicks the button to actually release.
- Continuous Deployment — one step further: passing changes go straight to production automatically, no human button.
The only difference between the two CDs is that last manual gate. Delivery = “always ready to ship, we choose when”. Deployment = “if it’s green, it’s live”.
A typical pipeline
A pipeline is a series of stages; if any stage fails, the whole thing stops and nothing ships. Each stage is a gate.
# a stripped-down GitHub Actions pipeline
on: [push]
jobs:
ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci # build
- run: npm test # test
- run: npm audit # scan
- run: ./build.sh # deploy: build image + push to registry
The build usually produces one immutable artifact (a Docker image) that’s promoted unchanged through staging to production — so what we tested is exactly what runs. No rebuilding per environment.
The 12-Factor App
The twelve-factor app is a set of principles for building services that are easy to deploy, scale, and run in the cloud. We won’t recite all twelve like a shopping list — that’s a red flag in an interview. Instead, here are the ones that actually shape backend design.
-
Config in the environment. Anything that differs between environments (DB URLs, API keys, feature flags) lives in env vars, never hardcoded or committed. Why? One identical build runs everywhere; only the env changes. It also keeps secrets out of git.
# same image, different env per environment DATABASE_URL=postgres://prod-db:5432/app LOG_LEVEL=info -
Stateless processes. Our app processes should keep no important state in local memory or disk between requests. Any state that must persist goes to a backing service (DB, Redis). Why? So we can kill, restart, and scale processes freely — and any instance can handle any request. Store sessions in Redis, not in-process. This is what makes horizontal scaling work.
-
Backing services are attached resources. A database, cache, or queue is just a resource we reach by URL, swappable without a code change. Local Postgres and managed cloud Postgres should be interchangeable by flipping one env var — no code edits.
-
Logs as event streams. The app doesn’t manage log files. It just writes to stdout as a stream, and the platform captures, routes, and stores it. Why? The app shouldn’t care where logs end up — that’s the environment’s job. (This is exactly why structured stdout logging pairs so well with containers.)
-
Dev/prod parity. Keep development, staging, and production as similar as possible — same backing services, same OS, same config shape. Why? The bigger the gap, the more “worked in dev, broke in prod” surprises. Containers help enormously here.
There’s also disposability — start fast, shut down gracefully on SIGTERM — which ties straight into health checks and graceful shutdown.
Interview soundbite
CI is merging to main frequently with automatic build + test on every change; CD is either continuous delivery (always deployable, human clicks release) or continuous deployment (green means live, no human). A pipeline gates build → test → scan → deploy, promoting one immutable artifact through environments. The 12-factor rules that matter most for backend: config in env vars, stateless processes (state in backing services so we scale horizontally), attached backing services, logs to stdout as streams, and dev/prod parity.