All Writing
DevOps7 min read

How CI/CD actually works.

From a single git push to code running in production, automatically — every gate explained, in order.

Before CI/CD, shipping code meant someone manually running tests, manually building, and manually copying files to a server — slow, and one tired afternoon away from a mistake. CI/CD replaces all of that with a pipeline: a fixed sequence of automated steps that runs the exact same way, every single time.

The one-sentence version
CI proves a change is safe (tests, lint, build); CD takes an already-proven change and gets it running in front of real users, without a human copying files by hand.

CI and CD are two different machines

They’re almost always said together, but they trigger on different events and answer different questions.

Continuous Integration

  • Triggers on every push or pull request
  • Question it answers: "is this change safe?"
  • Lint, type-check, tests, build — nothing touches production
  • Blocks merging if anything fails

Continuous Deployment

  • Triggers after a merge to the main branch
  • Question it answers: "can real users have this now?"
  • Builds the real artifact once, ships it to staging, then prod
  • "Continuous Delivery" is the same thing with a manual approval gate

Continuous Integration — what runs on every push

This is the pipeline a developer sees on every single pull request, usually finishing in a few minutes.

1
Push / PR
Step 1 of 7Trigger

A developer pushes a commit or opens a pull request. This is the event that kicks everything else off — no human has to remember to run anything.

Continuous Deployment — what runs after merge

Once code lands on main, a second, separate pipeline takes over — this one is allowed to touch real infrastructure.

1
Merge to Main
Step 1 of 7Trigger

Once the PR is approved and every CI check is green, it merges into the main branch — the signal that this code is ready to ship.

What the config actually looks like

Most CI/CD systems are configured with a YAML file checked into the repo itself — so the pipeline is version-controlled right alongside the code it tests. A trimmed-down GitHub Actions example for the CI half:

.github/workflows/ci.yml
1on:
2 pull_request:
3 branches: [main]
4
5jobs:
6 test:
7 runs-on: ubuntu-latest
8 steps:
9 - uses: actions/checkout@v4
10 - uses: actions/setup-node@v4
11 - run: npm ci
12 - run: npm run lint
13 - run: npm test
14 - run: npm run build

Four lines of actual work (npm ci, lint, test, build) is the entire CI pipeline from the earlier diagram — the rest is the platform wiring the trigger, the runner, and the pass/fail status back to the pull request automatically.

Common mistake
Treating “the pipeline is green” as proof the app works in production. CI runs against a clean, isolated environment — it can’t catch a missing production environment variable, a real third-party API being down, or a database migration that only breaks at real scale. Smoke tests after deploy exist specifically to catch that gap.

Why teams bother with all of this

  • Consistency. The exact same steps run on a fresh machine every time — no “works on my laptop” surprises.
  • Speed. Catching a broken test in 3 minutes on a PR is cheap; catching it after it’s live is expensive.
  • Confidence to ship often. Teams that trust their pipeline deploy multiple times a day instead of once a quarter — smaller changes are easier to debug when something does go wrong.
  • Fast, safe rollback. Because every deploy is just “run the same pipeline with the previous commit,” undoing a bad release is one click, not a fire drill.

2–8 minutes

Typical CI run time

Multiple times / day

Elite teams deploy

Auto, on error spike

Rollback trigger

In practice
This very site ships that way — every push runs lint, tests, and a production build in CI (see .github/workflows/ci.yml in this repo) before anything reaches the live site.