Deployment Strategies
Six ways to replace running code, compared on how they work, what they risk, what they cost, how you get back, and what each is actually for.
The question, the obvious approach, and why it breaks
Every lesson starts where the work starts: an operational problem, a first attempt that is entirely reasonable, and the way production disagrees with it.
Every strategy replaces running code with new code — so what actually differs between them, and how do I choose one for this change?
A running system is serving requests right now, and you need it to be running different code. There is no way to do that which is simultaneously instant, free, reversible and exposure-free, so every strategy trades one of those away.
Pick the strategy the platform defaults to. Kubernetes rolls, so we roll; the PaaS swaps slots, so we swap slots. It has worked so far.
The default is chosen for the common case, and the change that hurts you is the uncommon one — the migration, the cache format change, the singleton job that must not run twice.
- The default is chosen for the common case, and the change that hurts you is the uncommon one — the migration, the cache format change, the singleton job that must not run twice.
- A rolling default silently assumes two versions of your code can run at once against the same database, cache and queue. Nothing checks that assumption, and it is false more often than teams expect (Version Coexistence: N and N+1, in Both Directions).
- Teams discover the rollback semantics of their strategy during the incident that needs them. Rolling back a rolling deploy takes as long as the rollout did; rolling back a recreate deploy is a second outage.
- Choosing per-platform rather than per-change means the riskiest change of the quarter ships the same way as a copy edit (Change Size: Why Small Changes Are Safer, and When They Are Not).
What is actually happening
Underneath the tooling, which is the part that survives a change of tool.
- Strip the names away and three variables describe all of them: exposure (what share of traffic can see the new version at its worst moment), coexistence (whether old and new run at the same time, and for how long), and spare capacity (how much extra you must be running to do it at all).
- Recreate has zero exposure to a mixed state and total exposure to downtime. Rolling trades a long mixed window for almost no spare capacity. Blue/green buys instant reversal with a second environment. Canary buys bounded exposure with time and traffic-routing machinery. Shadow removes exposure entirely by discarding the answers. Flags move the whole question out of the deploy and into configuration.
- The strategy controls the code path. It does not control shared state: the database, the cache, the queue and the object store are the same ones before and after, which is why the hardest part of any strategy is what the *other* version does to them (A Migration and a Deploy Are One Event).
- Rollback is a deployment too, and it inherits the strategy's properties. A strategy is only as good as its reverse.
The six strategies, on the five things that matter
This table is the module in one screen. Everything after it is an expansion of one row. The column that people skip is the fourth one: rollback is a property of the strategy, not a separate capability you can add afterwards.
| Strategy | How it works | Risk if the new version is bad | Cost | Rollback | Best use case |
|---|---|---|---|---|---|
| Recreate | Stop every old instance, then start the new ones | Total but brief for the bad code; if the new version fails to start, the outage simply continues | Cheapest — no spare capacity, no coexistence work | Deploy the old artifact: a second outage window | Single-instance services, batch workers, and versions that genuinely cannot coexist |
| Rolling | Replace instances in batches; old and new serve simultaneously until the last batch | Proportional to how far the rollout reached before anyone noticed | One batch of surge capacity, plus the permanent cost of coexistence-safe code | Another rolling deploy in reverse — same duration, same mixed window | The default for stateless, replicated services |
| Blue/green | Two complete environments; a router sends all traffic to exactly one of them | All-or-nothing: everyone is exposed the instant the router moves | Highest — a second environment, while the database stays shared | Move the router back; the fastest reversal on the menu | Changes that need reversal in seconds and are safe to expose all at once |
| Canary | A small share of real traffic on the new version, widened only while health holds | Bounded by the current step — one percent of users rather than all of them | Rolling cost plus traffic control and per-version telemetry | Return the current step to zero percent | Failures that only appear under real traffic, on services with enough traffic to read |
| Shadow | Real requests are duplicated to the candidate; its responses are discarded | None to users on the read path — the risk moves entirely to writes and side effects | A full second copy, plus doubled load on every shared dependency | Stop mirroring; there is nothing user-visible to undo | Proving crash and resource behaviour under real traffic before anyone depends on it |
| Feature flag | New code ships disabled; configuration enables it later, for whom you choose | Bounded by the targeting rule — and unbounded if the default on failure is wrong | Cheap in infrastructure, expensive in branches, tests and eventual deletion | Flip the flag: no deploy, seconds, and no pipeline in the way | Releasing behaviour independently of the artifact that carries it |
The question underneath the menu
People choose strategies by name and then discover the property they needed was somewhere else. The useful framing is to name the property first. Each option below buys exactly one thing and charges for it.
Note that two of these — shadow and flags — are not really deployment strategies at all. Shadow moves the candidate out of the serving path; flags move the decision out of the deploy. They belong on the same list because they answer the same underlying question about exposure.
What are you trying to buy for this specific change?
when Two versions genuinely cannot run at once: an exclusive lock, a singleton scheduler, an on-disk format only one of them understands.
cost Downtime for the whole stop-start-warm window, and a second window to get back.
when The service is stateless and replicated, and every version can read and write the shared state every other version can.
cost A mixed-version window on every deploy and every rollback, which every change from now on must be designed for.
when You need to be able to undo in seconds, and the change is safe to expose to everyone at once.
cost A second environment, and no reduction in exposure whatsoever — only in time to reverse.
when The failure you fear only appears under real traffic, and you have enough traffic that a small slice produces a readable signal.
cost Slow rollouts, traffic-routing machinery, and telemetry that can distinguish the versions.
when You want production traffic through the candidate before any user depends on the result, and the path has no writes or external side effects.
cost Duplicate capacity, doubled load on shared dependencies, and it still proves nothing about writes.
when The unit you want to control is a feature or a customer, not an artifact version.
cost Branching in code that must be tested in combination, owned, and eventually deleted (Feature Flags: Deploy Is Not Release).
What your platform will actually let you have
Strategy availability is a property of the runtime, and the gap between the textbook menu and what you can do this afternoon is large. The row that surprises people most is the autoscaling group: traffic share is quantised by instance count, so with four instances the smallest canary you can express by replica count is a quarter of your traffic.
| Platform | Rolling | Blue/green | Canary by traffic share | What actually differs |
|---|---|---|---|---|
| One VM, one process | Nothing to roll | Only by standing up a second VM and moving a name | No | With a single instance every strategy degenerates into recreate; partial exposure does not exist |
| VM group behind a load balancer | Yes, by refreshing instances in batches | Yes — two groups, swap which one the balancer targets | Approximated by instance count | Exposure is quantised: the smallest slice you can express is one instance's share of traffic |
| Managed app platform (PaaS) | Usually the only mode, and usually automatic | Often built in as a staged copy plus a swap | Sometimes, as a percentage split between versions | You get the strategies the product ships; assembling your own is mostly not possible |
| Kubernetes | Built in — the Deployment rolling update | Not built in: two Deployments and a Service selector, or a service mesh | Not built in: an ingress or mesh that splits by weight, or a rollout controller | Kubernetes natively offers rolling and recreate. Canary and blue/green are things you add, and they are where the operational complexity lands |
| Serverless functions | Not applicable — you do not own instances | Version aliases pointing at one published version or another | Weighted split across versions, per invocation | The platform owns instance lifecycle entirely, so exposure is expressed purely as a weight over versions |
| Edge or CDN configuration | No | Sometimes, by activating a previous configuration version | Sometimes, by percentage or geography | Propagation is eventual and worldwide: there is no instance to drain, and reversal is a second propagation rather than an instant switch |
How to do it properly
Most important first.
- Choose per change, not per platform. The default handles ordinary changes; name the ones that are not ordinary and treat them deliberately.
- Before choosing, answer whether two versions may coexist. If the answer is no, most of the menu is unavailable to you and you should know that before the deploy starts (Version Coexistence: N and N+1, in Both Directions).
- Write down the reversal for the strategy you picked, in the same breath as the plan: what command, how long, and what it does not undo (Rollback: Only Useful If It Is Actually Safe).
- Separate the artifact rollout from the behaviour release where you can — a flag turns one risky deploy into two smaller, independently reversible decisions (Feature Flags: Deploy Is Not Release).
- Match the strategy to the blast radius you can accept, not to the one you would prefer (Blast Radius: If This Is Wrong, How Much Does It Affect?).
How much can this affect
Every production change has a blast radius. Stated as a scale so it is comparable between changes rather than adjectival — and paired with what actually contains it, because a wide scope with a real containment mechanism is a different situation from a wide scope with none.
Nothing — the choice of strategy is itself the containment mechanism. Choosing badly is exactly how a bad change reaches everyone, which is why this lesson sits before all the others in the module.
What can go wrong
- A strategy chosen for exposure control that provides none because the change is a shared-state change — a canary at 1% still writes the new schema for everyone.
- Rollback assumed to be symmetrical with rollout and discovered not to be, mid-incident.
- A canary or blue/green setup that exists in configuration but has never been exercised, so its first use is under pressure.
- Strategy machinery that becomes its own outage source: the traffic-splitting layer, the flag service, the second environment nobody patches.
- "Canary is the safest, so use it always." Canary bounds exposure to the *code path*. For a change whose risk lives in shared state, it bounds nothing while costing you a slow rollout.
- "Blue/green means zero risk." Blue/green means fast reversal. At the moment of cutover, 100% of traffic moves to code no user has touched yet.
- "The platform handles deployment, so this is not my problem." The platform moves bytes and reports success. Whether your two versions can coexist is a property of your code (A Successful Deploy Is Not Evidence of a Healthy System).
- "We do continuous deployment, so we do not need strategies." The more often you deploy, the more often you are in a mixed-version window, so coexistence matters *more*, not less.
Operating it
Evidence is the signal, not the intention. Rollback is sometimes 'you cannot, and that is the point'.
- For the last deploy you can say what share of users could have been affected at the worst moment, and what would have limited it.
- The reversal has been performed at least once outside an incident, and how long it took is a known number rather than an estimate.
- The mixed-version window is a designed property — you know it exists, how long it lasts, and what runs during it.
- Recreate: deploy the previous artifact, accepting a second downtime window.
- Rolling: a rolling deploy in the other direction, taking about as long and passing through the same mixed state.
- Blue/green: point the router back at the environment still running the old version — the fastest reversal available, and the reason people pay for it.
- Canary: set the current step back to zero percent, which affects only the users on that step.
- Flags: flip the flag, which needs no deploy at all and is therefore the fastest of all — and the least reviewed.
- Automate the mechanics completely: batching, health gating, traffic weights, and the abort path. A human editing weights by hand during a rollout is a source of incidents.
- Keep the choice of strategy for a specific risky change with a human. It depends on knowledge of the change that no pipeline has.
- Safer strategies are slower. A canary that observes at every step turns a two-minute deploy into a long one, and long rollouts overlap with each other and with incidents.
- Exposure control costs infrastructure — a second environment, a traffic-splitting layer, per-version telemetry — and all of it must be maintained whether or not you are deploying.
- Coexistence-tolerant code is more complex code: tolerant readers, additive migrations, two paths where there was one (Expand, Migrate, Contract).
Where this applies
This domain is unusually tool- and organisation-dependent. These labels say what each claim is specific to, and what a different platform, provider or organisation does instead.
- PLATFORM-SPECIFICWhich strategies are even available is decided by the runtime. A managed app platform hands you two or three as product features and nothing else; Kubernetes gives you rolling natively and makes canary and blue/green things you assemble; a single VM makes every strategy degenerate into recreate. The trade-offs are universal, the availability is not.
- GENERALThe three variables — exposure, coexistence, spare capacity — describe deployment on any platform, including ones that do not exist yet. The strategy names are conventions on top of them.
Where the depth lives
This domain teaches delivery and operation, and hands the mechanism off to the domain that owns it.
- — Testing & Reliability Engineering — how much confidence a test suite can supply before any of these strategies is needed.