Deployment & CI/CD Basics
What actually happens between pushing a code change and that change running live for real users, at a conceptual level.
What is it?
Writing code that works on your own laptop is only part of the job — it still needs to get onto a real server somewhere, running in a way real users can reach, without breaking whatever was already working. Doing that by hand each time (manually copying files to a server, restarting things, hoping nothing was forgotten) is slow and error-prone, especially as a team grows.
CI/CD stands for Continuous Integration and Continuous Deployment (or Delivery). Continuous integration means every code change is automatically built and tested the moment it's pushed, to catch problems early rather than after they've piled up. Continuous deployment (or delivery) means that once a change passes those checks, it's automatically (or with one click) shipped out to run in production, following the same repeatable steps every single time.
Explain like I'm 10
Think of an assembly line at a factory versus a single craftsperson manually building one product at a time by hand. The assembly line runs the exact same checks and steps on every single item — the same quality inspection, the same packaging process — every time, catching defects early and shipping consistently, instead of relying on a person to remember every step correctly by hand each time.
Examples
A CI pipeline definition
# .github/workflows/ci.yml (conceptual)
name: CI
on: [push]
jobs:
test:
steps:
- run: npm install
- run: npm run build
- run: npm testEvery time code is pushed, this pipeline automatically installs dependencies, builds the project, and runs the test suite — without anyone needing to remember to do it manually.
A deployment step that only runs after tests pass
jobs:
test:
steps:
- run: npm test
deploy:
needs: test # only runs if the "test" job succeeded
steps:
- run: ./deploy.sh productionThe deploy job is deliberately gated on the test job succeeding first, so broken code never gets a chance to reach production.
How it works
When code is pushed, a CI/CD system automatically runs a defined sequence of steps: installing dependencies, building the project (if it needs a build step), running the automated test suite, and sometimes additional checks like linting or security scanning. If every step succeeds, a deployment step can run: packaging the app (often as a container image), pushing it to a hosting platform or server, and switching live traffic over to the new version — ideally with a way to quickly roll back if something still goes wrong once it's live.
Why does it exist?
Manual deployment is slow, inconsistent, and entirely dependent on a human remembering every step correctly, every single time — which inevitably fails as a team and codebase grow. CI/CD exists to make shipping code a repeatable, automated, and verified process: every change gets the same checks applied to it, and getting a fix or feature live becomes fast and low-risk instead of a stressful, manual ritual.
When to use it
Set up CI from the very start of a real project — even a single automated test run on every push catches obvious mistakes early. Add continuous deployment once you have enough test coverage and confidence that a passing pipeline genuinely means the change is safe to ship.
When not to use it
For a throwaway prototype or a script that will only ever run once, manually, setting up a full pipeline is unnecessary ceremony — the investment pays off once code is going to be deployed and iterated on repeatedly, not for one-off work.
Common mistakes
Deploying automatically even when tests fail, defeating the entire purpose of having tests gate the pipeline.
Having no way to quickly roll back a bad deployment once it's already live.
Treating a green CI pipeline as proof that everything is fine, when the test suite itself doesn't actually cover the part of the app that broke.
Practice exercises
- Easy:
Describe, in order, the steps you'd expect a CI pipeline to run for a typical Node.js backend project.
- Medium:
Explain why a deployment step should be configured to run only after the test step succeeds, and what could go wrong if it wasn't.
- Hard:
Describe a rollback strategy for a deployment that turns out to have a serious bug discovered only after it reached production.
Interview questions
What does CI/CD stand for, and what does each part mean?
Continuous Integration (automatically building and testing every code change as it's pushed) and Continuous Deployment/Delivery (automatically or reliably shipping a change that passes those checks out to production).
Why is it important that deployment only happens after tests pass?
Because it prevents broken or untested code from ever reaching production automatically — the test suite acts as a gate the change must pass first.
Why is manual deployment risky as a team or codebase grows?
It relies on a person correctly remembering and performing every step every time, which becomes increasingly error-prone and inconsistent as complexity and team size increase.
What is a blue-green deployment?
Two identical production environments exist — 'blue,' the currently live one, and 'green,' the new version. Green is deployed and verified while blue keeps serving all real traffic, then traffic is switched to green all at once, leaving blue in place as an instant rollback target.
What is a rolling deployment?
New-version instances are brought up and old ones taken down gradually, a few at a time, rather than switching everything over at once — so at any moment during the rollout, both old and new versions are simultaneously serving live traffic.
What's a key tradeoff between blue-green and rolling deployment?
Blue-green needs double the infrastructure running at once but gives instant, clean rollback with no mixed-version traffic; rolling deployment uses less extra infrastructure but runs old and new versions side by side during the rollout, which is a problem if they aren't compatible.
What is a canary deployment?
The new version is rolled out to a small subset of real traffic or users first and monitored for problems, only being rolled out further once it looks healthy — limiting the blast radius of a bad deploy compared to shipping to everyone at once.
Why does a database migration need special care during a rolling or blue-green deployment?
Old and new application code query the same database at the same time during the rollout, so a migration that removes or renames a column the old code still expects would break the still-running old instances before they're fully retired.
What is a CI pipeline's build step generally responsible for, beyond installing dependencies?
Compiling or transpiling source code, bundling assets, or otherwise producing the actual runnable artifact that will later be tested and deployed — e.g. type-checking plus bundling for a TypeScript project.
Why does `needs: test` on the deploy job matter mechanically, not just as convention?
It tells the CI system the deploy job must not even start until the test job has finished and succeeded — if tests fail, deploy is skipped entirely rather than merely expected to be skipped.
What's the difference between continuous delivery and continuous deployment?
Continuous delivery verifies every change that passes the pipeline is ready to release, typically requiring one manual approval to actually ship it; continuous deployment goes further and ships it to production automatically, with no manual step at all.
Why is a build artifact often packaged as a container image?
A container image bundles the app together with its exact runtime and dependencies, so it runs identically wherever it's deployed, avoiding mismatches between the environment it was tested in and the one it actually runs in.
Why should the same build artifact that passed CI be the one deployed, rather than rebuilding from source at deploy time?
Rebuilding separately risks a different result — a dependency resolving differently, an environment difference — so what actually gets deployed was never the exact thing that was tested. Reusing the same artifact guarantees what was tested is what ships.
What does rollback mean in a deployment context, and why does it need to be fast?
Reverting production back to the last known-good version after a bad deploy is discovered live. The longer a broken version stays live, the more real users and requests are affected, so a slow rollback process extends that damage window.
How does blue-green deployment make rollback close to instant?
The previous version, blue, is still fully running and untouched after the switch to green — rolling back just means routing traffic back to blue, rather than rebuilding or redeploying the old version from scratch.
Scenario: a deploy passes CI, ships, and real users then hit errors no test caught. What does this reveal?
A green pipeline only proves the tests that exist all passed — it says nothing about behavior the suite never exercised, so this points to a gap in test coverage for that code path, not the pipeline itself misbehaving.
What is a health check, and what role does it play during a deployment?
An endpoint or process reporting whether a running instance is actually healthy and ready for traffic. A deployment system uses it to decide whether new instances are safe to receive traffic, or to automatically halt a rollout if new instances keep failing.
Why might a CI pipeline include a linting step in addition to tests?
Linting catches a class of problems tests don't check for directly — style inconsistencies, unused variables, certain likely bugs — using static analysis of the code rather than executing it.
Trap: a team's CI pipeline is green, but they still deploy manually by copying files to a server 'for now.' What risk does this defeat?
A passing pipeline is worthless as a safety guarantee if the deployment step itself isn't the same automated, repeatable process every time — manual deployment reintroduces exactly the human-error risk CI/CD exists to remove, regardless of how solid the CI checks are.
What secrets-related concern is specific to CI/CD pipelines?
A pipeline often needs credentials — deploy keys, API tokens — to actually push a deployment. These need secure storage, e.g. as encrypted pipeline secrets, rather than being committed in the pipeline definition file itself, which is often visible to anyone with repo access.
Why run the same test suite on every pull request, not just on the main branch after merging?
Catching a problem before it's merged means a broken change never lands on the branch other people build on top of, rather than needing to be found and reverted after the fact.
What does it mean for a deployment pipeline to be idempotent, and why does that matter?
Running the same deployment step twice in a row, e.g. after a retry, produces the same end result rather than compounding an effect. This matters because pipelines sometimes do need to retry a step after a transient failure, like a flaky network call.
Follow-up: is a fast rollback path alone enough to guarantee a bad deploy is safe?
Not by itself — you also need monitoring and alerting to actually detect the bad deploy quickly. A fast rollback that isn't triggered until users have already been affected for hours limits the damage far less than it could.
How does a canary deployment differ from A/B testing, even though both route a subset of traffic differently?
A canary is purely about deployment safety — verifying the new version behaves correctly before a full rollout, usually briefly. A/B testing deliberately compares two versions' real-world outcomes, often over a longer period, to decide which is better, not to safety-check a release.
Advanced: why might a rolling deployment be a poor fit for a breaking database schema change, even with careful ordering?
Old and new code must both work correctly against whatever schema state exists during the rollout window. Some schema changes have no safe intermediate state satisfying both versions' expectations at once, forcing a different strategy, like a multi-step expand-and-contract migration.