Rolling, blue/green and canary
coreadvancedA **rolling** deploy replaces instances a few at a time, so both versions serve traffic while it runs. **Blue/green** brings up a whole second fleet, tests it, then switches all traffic at once — and switches back just as fast. A **canary** sends a small share of real traffic to the new version, watches the error rate, and only then continues. All three run two versions of your code against **one** database.
Think of it as
The three differ in one variable — what fraction of traffic the new version receives over time — and everything else follows from that. Rolling ramps: 25%, 50%, 75%, 100% as instances are replaced, using no extra capacity because each new instance takes a retired one's place. That makes it the cheap default, and its cost is that both versions are live throughout, so a bug is exposed to a growing share of users and the rollback is another full roll. Blue/green steps: the green fleet is built and warmed with no traffic, smoke-tested for real, then the load balancer switches everything at once. You pay for double capacity during the switch and you gain the fastest possible rollback — flip back to blue, which is still running and still warm. Canary holds: a small slice, maybe 5%, goes to the new version while you watch error rate and latency for that slice specifically, and only when it looks right do you continue. It is the only one of the three that gives you evidence from production before full exposure, and it costs the machinery to route by share and to compare metrics *per version*, which is worth naming because a canary without per-version metrics is just a slow rolling deploy. What unites them, and matters more in Django than the choice itself, is that they all put two versions of your application in front of one database. Nothing about the strategy changes that: blue and green share the schema, the canary shares it with the stable fleet, and a rolling deploy has both versions writing rows for minutes. So the schema in effect during a deploy has to satisfy the old code and the new code simultaneously, which is exactly the expand-and-contract discipline — add the column, deploy code that writes both shapes, switch reads, and remove the old shape in a later release. Get that wrong and the strategy makes it worse rather than better: a canary that drops a column takes down the 95% that did not receive the new code. Two smaller consequences are worth holding. Sessions and caches are shared too, so a change to what you store in a session or under a cache key has to be readable by both versions or the deploy shows up as random logouts. And background workers are a third fleet: if a task signature changes, the old workers are still consuming messages the new code produced, so tasks need the same backward-compatibility treatment as the schema.
What we're doing: Ship a change that adds a column and a new read path, using a canary, without ever putting the database in a state one of the two live versions cannot use.
- 3–6
- The migration is deliberately additive and goes out *before* the code that uses it. A nullable column with a default is invisible to the version that does not know about it.
- 8–10
- The canary writes the new column but still reads the old source, so the two live versions cannot disagree about what an order means while both are serving.
- 11–15
- Metrics compared *per version*. Without that split the canary's errors are five per cent of a number that looks unchanged, which is why a canary without per-version metrics is just a slow roll.
- 21–22
- The queue is the fleet people forget. Adding an optional argument keeps old workers able to consume new messages; renaming the task would strand every message already queued.
- 24–26
- The backfill is out of band because it is long, batched and resumable. Putting it in the deploy makes the release as slow as the largest table.
- 32–35
- The contract step is a separate release, and the point at which rollback stops being available is written down. That sentence is the difference between a planned constraint and an incident.
Why this works: At every moment the database satisfies both deployed versions, the canary produces per-version evidence before full exposure, and the release where rollback stops working is named in advance.
Canarying a release that contains a destructive migration
Wrong
Better
What you see: The canary looks perfect and the site goes down. The 5% on the new code is fine; the 95% on the old code is raising `column orders.legacy_channel does not exist` on nearly every request.
Why: A canary limits exposure to the new *code*, and a migration is not code — it is a change to shared state that every version sees at once. So a destructive migration inverts the safety property completely: the smaller the canary, the larger the fraction of traffic broken by it. This is the clearest illustration of the rule the whole section rests on: during any of these strategies the schema must satisfy both versions, and the only way to get that with a removal is to postpone the removal to a later release. If a change genuinely cannot be made additive, then it cannot be canaried or rolled either, and the deployment needs a maintenance window stated in advance.
- Three small step charts side by side, each plotting the share of traffic served by the new version against time, from zero per cent at the bottom to one hundred per cent at the top.
- Rolling is a staircase climbing in four equal steps from zero to one hundred per cent, labelled "no extra capacity, both versions live throughout".
- Blue/green is flat at zero and then jumps straight to one hundred per cent in a single step, labelled "double capacity briefly, and the fastest rollback".
- Canary is flat at zero, rises to a narrow five per cent shelf that it holds for a long stretch, then jumps to one hundred per cent, labelled "evidence from real traffic before full exposure".
- A footer states that in all three cases both versions share one database, one cache and one queue, so the schema in effect must satisfy the old code and the new code at the same time.
The three strategies, compared on what they actually cost
Together
What must be compatible across the two live versions
Together
Remember: The three strategies differ only in how fast the new version reaches 100% of traffic: rolling ramps with no extra capacity, blue/green steps with double capacity and the fastest rollback, and a canary holds a small share while you gather real evidence. All of them run two versions of the code against one database, one cache and one queue, so the schema, the session format, the cache values and the task payloads must all satisfy both versions at once — which is expand-and-contract, not a strategy choice. And a canary only works with per-version metrics; without them, five per cent of the errors disappears into normal variation.
See also: feature flags separate release from deploy · rollback planning and the migration problem · the expand and contract technique · artifacts approvals and rollback

