All chapters in this track
- 01Chapter 1: Why the SDLC Matters
- 02Chapter 2: An Honest Comparison of SDLC Models: Waterfall, Iterative, Agile/Scrum, Kanban, Lean, Spiral, DevOps
- 03Chapter 3: Choosing and Adapting a Model for Team Size, Domain, and Risk Tolerance
- 04Chapter 4: Requirements Gathering and Analysis
- 05Chapter 5: The Design Phase and Its Connection to HLD/LLD
- 06Chapter 6: Implementation Practices That Keep a Project Healthy
- 07Chapter 7: Testing Strategy Across the Pyramid
- 08Chapter 8: Documentation Across the Lifecycle: Specs, ADRs, Runbooks
- 09Chapter 9: Release and Deployment: CI/CD, Versioning, Blue-Green and Canary Releases, Feature Flags
- 10Chapter 10: Operations and Maintenance: On-Call, Monitoring, Incident Response
- 11Chapter 11: Measuring Delivery Health: Cycle Time, Deployment Frequency, Change Failure Rate, MTTR
- 12Chapter 12: Case Study: The SDLC in a Five-Person Startup
- 13Chapter 13: Case Study: The SDLC in a Large Enterprise Team
- 14Chapter 14: Worked Example: Choosing a Process for a New Team
- 15Chapter 15: Common Interview Questions About the SDLC
Chapter 9 of 15
Chapter 9: Release and Deployment: CI/CD, Versioning, Blue-Green and Canary Releases, Feature Flags
Why this matters
Chapter 2 mentioned DevOps and continuous delivery as answering "how does software get from done to running in production" — this chapter covers exactly that question in depth, since deployment is where a huge share of real production incidents originate, and where a small set of well-understood techniques dramatically reduce the risk of any single release causing an outage.
CI/CD: the automated pipeline from commit to production
[BEGINNER] Continuous Integration (CI) automatically builds and tests every change as it's committed (companion Coding Standards book, Chapter 11's CI-gate discussion); Continuous Deployment/Delivery (CD) automatically (or with a single manual approval click) takes a change that's passed CI all the way to production, rather than deployment being a separate, manual, error-prone process run occasionally by a person.
# A representative GitHub Actions CI/CD pipeline
name: CI/CD
on: [push]
jobs:
build-and-test:
steps:
- run: npm run lint
- run: npm test
- run: npm run build
deploy:
needs: build-and-test
if: github.ref == 'refs/heads/main'
steps:
- run: ./deploy.sh production
[SENIOR INSIGHT] The deep value of CI/CD isn't just "automation saves time" (though it does) — it's that frequent, small, automated deployments are inherently lower-risk than infrequent, large, manual ones, directly connecting to Chapter 6's trunk-based development discussion: a deployment containing one small change is easy to reason about and easy to roll back cleanly if something goes wrong; a deployment containing three weeks of accumulated changes (common when deployment is manual, infrequent, and treated as a big event) makes it much harder to identify which specific change caused a problem if one appears.
Semantic versioning: communicating the nature of a change through its version number
[BEGINNER] Semantic versioning (SemVer) — MAJOR.MINOR.PATCH — communicates what kind of change a new version represents, specifically for software consumed by other people/systems (a library, a public API): MAJOR increments for breaking changes, MINOR for backward-compatible new functionality, PATCH for backward-compatible bug fixes. This lets a consumer decide how cautiously to upgrade based purely on the version number, without needing to read a full changelog for every single update.
1.2.3 -> 1.2.4 (PATCH: a bug fix, safe to upgrade without review)
1.2.3 -> 1.3.0 (MINOR: new functionality added, backward-compatible)
1.2.3 -> 2.0.0 (MAJOR: a breaking change -- review before upgrading)
Blue-green deployment: instant, safe cutover with an easy rollback
[BEGINNER] Blue-green deployment maintains two complete, identical production environments ("blue" and "green") — only one serves live traffic at any time. A new version deploys entirely to the currently-inactive environment, gets verified there, and then traffic is switched over all at once (typically via a load balancer/router configuration change, companion Networking book Chapter 8) — with the previous environment left running and ready, making rollback as simple as switching traffic back.
Before: Router --> [Blue: v1.2, LIVE] [Green: idle]
Deploy v1.3 to the IDLE environment and verify it:
Router --> [Blue: v1.2, LIVE] [Green: v1.3, verified, NOT yet live]
Cut over:
Router --> [Blue: v1.2, idle] [Green: v1.3, LIVE]
If a problem is found: instant rollback by switching the router back to Blue.
Trade-off: requires running double the infrastructure (two complete environments) even though only one serves traffic at a time — a real cost, justified specifically by the instant, clean rollback capability it provides.
Canary deployment: gradual, risk-limited rollout
[BEGINNER] Canary deployment (named after the historical practice of using canaries to detect dangerous gas in mines) releases a new version to a small subset of traffic/users first, monitors for problems, and gradually increases the rollout percentage if things look healthy — rather than blue-green's all-at-once cutover.
Stage 1: 5% of traffic -> v1.3, 95% -> v1.2 (monitor error rates/latency)
Stage 2 (if healthy): 25% -> v1.3, 75% -> v1.2
Stage 3 (if healthy): 100% -> v1.3
At any stage, if metrics degrade: roll back to 0% v1.3 immediately.
Trade-off vs. blue-green: canary limits the blast radius of a bad release (only a small percentage of users are affected before a problem is caught) but is inherently slower to fully roll out and requires good monitoring/metrics to actually detect a problem during the gradual rollout — blue-green's instant, all-at-once cutover is faster but exposes 100% of traffic to a new version immediately upon cutover, with no gradual exposure limiting the blast radius of an undetected problem.
Feature flags: decoupling deployment from release
[SENIOR INSIGHT] A feature flag wraps new functionality in a runtime-configurable toggle, letting code be deployed to production while remaining invisible/inactive to users until explicitly turned on — this is the single most important concept in this chapter for understanding modern release practice, because it decouples deployment (code reaching production) from release (a feature becoming visible/active to users), two things that used to be treated as the same event.
if (featureFlags.isEnabled("new-checkout-flow", user)) {
return renderNewCheckoutFlow();
} else {
return renderOldCheckoutFlow();
}
This decoupling directly enables Chapter 6's trunk-based development (merge incomplete work continuously, hidden behind a flag), safer canary-style rollouts at the feature level rather than just the infrastructure level (enable a flag for 5% of users, independent of any infrastructure deployment), and instant "rollback" of a problematic feature (flip the flag off) without needing a full code deployment/rollback at all — often faster and lower-risk than any infrastructure-level rollback mechanism.
Common mistakes
- Treating deployment as a rare, large, manual event rather than investing in CI/CD automation that makes frequent, small, low-risk deployments the norm.
- Not using semantic versioning meaningfully (e.g., bumping only the patch version for an actual breaking change), misleading consumers about the safety of upgrading and undermining the entire point of the versioning scheme.
- Choosing blue-green when canary's gradual, blast-radius-limiting rollout would better fit a genuinely risky change, or vice versa — using the same deployment strategy uniformly regardless of a specific release's actual risk profile.
- Conflating deployment and release, missing the real flexibility feature flags provide by decoupling "code is in production" from "users can see/use it" — this conflation is exactly what makes trunk-based development and safe incremental feature rollout harder than they need to be.
Discussion / interview questions
-
"Why are frequent, small, automated deployments generally lower-risk than infrequent, large, manual ones?" Strong answer: A small deployment is easy to reason about and easy to cleanly roll back if something goes wrong; a large deployment bundling weeks of changes makes it much harder to identify which specific change caused a problem if one appears — directly connecting to trunk-based development's small, frequent integration principle.
-
"What's the difference between blue-green and canary deployment, and when would you choose one over the other?" Strong answer: Blue-green does an instant, all-at-once cutover between two complete environments (fast, easy rollback, but exposes 100% of traffic immediately); canary gradually increases a new version's traffic share while monitoring (limits blast radius of a bad release, but slower and requires good monitoring) — canary fits higher-risk changes better; blue-green fits situations valuing speed and simplicity where the risk is already well-understood/low.
-
"What does it mean to 'decouple deployment from release,' and how do feature flags enable this?" Strong answer: Deployment (code reaching production) and release (a feature becoming visible/active to users) are traditionally the same event; feature flags let code deploy while remaining inactive until explicitly toggled on, enabling continuous integration of incomplete work (trunk-based development), feature-level gradual rollouts independent of infrastructure deployments, and instant flag-based "rollback" without a full code rollback.
-
"Why does semantic versioning matter for a library or public API?" Strong answer: It communicates the nature of a change (breaking, new-but-compatible, bug-fix-only) directly through the version number, letting consumers decide how cautiously to upgrade without needing to read a full changelog for every release — this only works if version bumps are applied meaningfully and consistently.
Chapter summary / cheat sheet
- CI/CD automates the build-test-deploy pipeline, making frequent, small, low-risk deployments the norm instead of rare, large, manual, higher-risk events.
- Semantic versioning (
MAJOR.MINOR.PATCH) communicates a change's nature directly through its version number, informing consumers' upgrade caution. - Blue-green deployment: instant, all-at-once cutover between two complete environments — fast, easy rollback, but no gradual blast-radius limiting.
- Canary deployment: gradual traffic rollout with monitoring at each stage — limits blast radius, slower, needs good metrics.
- Feature flags decouple deployment from release, enabling trunk-based development, feature-level gradual rollout, and instant flag-based rollback — arguably the single most important modern release concept in this chapter.