What Is Progressive Delivery? A Guide for Dev Teams
Summary
What is progressive delivery? It is a release approach where a change reaches production in small, controlled steps, and each step is checked against real metrics before the next one starts. It separates deploying code from releasing it to users, combines canary releases, blue-green deployments and feature flags, and relies on automated rollback when error rate or latency crosses a threshold you defined in advance.
What is progressive delivery? It is a way of releasing software where a change reaches production in small, controlled steps, and each step is checked against real metrics before the next one starts. If the numbers go bad, the release stops or rolls back by itself. You are no longer betting the whole user base on one deploy.
Here is the situation you probably know. A pull request is approved, CI is green, the deploy goes out on a Tuesday afternoon, and twenty minutes later someone in Slack asks why checkout latency doubled. Progressive delivery exists to make that conversation shorter, and to make it happen to 5% of traffic instead of 100%.
What does progressive delivery actually change?
Classic continuous delivery answers one question: can we ship this safely to production? Progressive delivery adds a second one: who sees it first, and what tells us to stop?
The core move is separating deploying from releasing. Deploying means the new code is running on servers. Releasing means users are exposed to it. Once those two are decoupled, you can deploy at 2 p.m. on a Wednesday and release at your own pace, to a chosen audience, with a way back.
Most of the sources you will read agree on three building blocks: gradual traffic shifting (canary), parallel environments (blue-green), and feature flags. They are not rivals. Mature teams use all three at different layers.
Canary releases: how much traffic, and who decides?
A canary release sends a small slice of traffic to the new version, say 5%, while the rest stays on the old one. If error rate, latency and saturation stay inside your thresholds, the slice grows: 5%, 25%, 50%, 100%. If they do not, traffic goes back.
The catch is that fine-grained splits need something that can split traffic. Argo Rollouts documents that precise canary percentages require a traffic manager such as a service mesh or an ingress controller. Without one, you only get coarse control based on replica counts, so "5%" may really mean "one pod out of twenty".
Here is what a staged canary looks like in an Argo Rollouts manifest. It is short on purpose.
strategy:
canary:
steps:
- setWeight: 5
- pause: { duration: 10m } # watch dashboards or run analysis
- setWeight: 25
- pause: { duration: 10m }
- setWeight: 100Skip a canary if your service sees so little traffic that 5% is a handful of requests per hour. You will wait forever for a signal, or worse, read noise as safety. For low-traffic services, feature flags targeted at internal users are a better first gate.

Blue-green deployments: when is a full second environment worth it?
Blue-green runs two complete production environments. Blue serves users. Green gets the new version and is tested while idle. When you are satisfied, traffic switches from one to the other.
According to the Argo Rollouts docs, the switch is all at once: the old version keeps all production traffic until the new one is verified, and then the split goes from 0% to 100%. That is the strength and the weakness. Rollback is a single flip back, which is fast. But the test happens before real users arrive, and the cost is double the infrastructure while both sides run.
Worth it if you ship a stateful or high-stakes service where a partial rollout would be confusing, for example a payment path where two versions must never both handle a request. Skip it if your database migration cannot run on both versions at once, because then the "instant rollback" is a fiction.

Where do feature flags fit?
Canary and blue-green work at the infrastructure level. Feature flags work inside the application. A flag wraps a code path in a conditional that you can change at runtime, without a redeploy.
That makes flags the finest-grained tool in the box. You can expose a feature to employees, then to 1% of accounts, then to one customer segment, and kill it in seconds if it misbehaves. Some teams treat flags as just one technique among several, while others call them the enabler of the whole approach. In practice the second view holds up: the moment you want to release by audience rather than by server, you need a flag.
Flags carry their own cost, though. Every flag is a branch your tests have to cover and a cleanup ticket someone has to close. If you want the longer version, we covered the mechanics and the debt in what a feature flag is. Treat each flag as short-lived by default, with an owner and a removal date.
Tools like LaunchDarkly and Statsig sell the management layer: targeting rules, audit logs, gradual percentage rollouts and experiments.
What makes a rollout progressive and not just slow?
Automation. A rollout that pauses for ten minutes while a human squints at a dashboard is a slow deploy. It becomes progressive delivery when a machine checks the metrics and makes the call.
The pattern is the same everywhere:
Define the signals before the release: error rate, p95 latency, one business metric such as checkout completion.
Define thresholds that mean "stop", written down in config, not in someone's head.
Let the controller promote, hold or roll back based on those signals.
Argo Rollouts integrates with metric providers so that a rollout can be promoted or aborted automatically depending on whether the checks pass. One of the sources we reviewed puts it bluntly: progressive delivery without automated rollback is just slow deployment. We agree.

Which metrics should gate a rollout?
Keep it to a small set. Three or four signals that you already trust beat twenty you have never alerted on.
A workable starting set: HTTP 5xx rate of the canary versus the baseline, p95 latency of the canary versus the baseline, saturation (CPU, memory, queue depth), and one product metric. Compare canary to baseline at the same moment, not canary to "last week", because traffic patterns shift.
This is where your observability stack stops being a nice-to-have. If you cannot slice metrics by version or by flag variant, you cannot tell the canary apart from the baseline, and the whole approach collapses. Our primer on what observability is covers how to get there.
How does progressive delivery relate to trunk-based development?
They fit together well. Trunk-based development keeps branches short and merges small changes often. The risk is that unfinished or untested work reaches main more frequently. Progressive delivery is what makes that safe: the code lands on trunk, ships dark behind a flag, and is released gradually.
Small batches plus gradual exposure also make debugging cheaper. When a canary fails, the suspect list is one change, not forty. Anyone who has bisected a week of merged commits at 11 p.m. knows what that is worth.
What is a realistic first step for a team of 10 to 30 engineers?
Do not start by installing a service mesh. Start with the smallest thing that gives you a stop button.
Week 1: put one risky feature behind a flag and release it to your own team first.
Week 2: add per-version dashboards for error rate and latency. If your tooling cannot split by version, fix that first.
Week 3 and beyond: move one stateless service to a canary controller with two or three steps and an automatic abort on error rate.
Measure it in hours, not in a "sentiment of safety". Count how many incidents were contained to a small slice of users, and how long the rollback took. Those two numbers will tell you whether it works for your team.
Where do progressive rollouts usually break?
Three places, and none of them is the controller.
Database migrations. A canary means two versions of your code hit the same database at the same time. If version N+1 drops or renames a column that version N still reads, the canary takes down the baseline. The boring fix is expand and contract: add the new column first, ship code that writes both, backfill, switch reads, and only later remove the old column.
Sticky sessions and caches. If a user bounces between old and new versions on every request, you get bugs that no one can reproduce. Pin users to a variant for the duration of the rollout, by cookie, by account id or by flag evaluation.
Metrics that lag. A conversion metric that updates hourly cannot gate a ten-minute canary step. Gate on fast signals (errors, latency) during the rollout, and review the slow business metric before you move from 50% to 100%.
How do you keep track of what is live in the repo?
Progressive delivery spreads a release across config files, flag definitions, rollout manifests and dashboards. After a few months, the question "which flag guards the new billing path, and who owns it?" turns into the usual routine: grep, blame, then asking someone.
That is a code reading problem, not a tooling one. Searching the repo by flag key and following each reference to its call site is the fastest way to find dead flags and half-finished rollouts. A tool that answers "where is this flag evaluated and what happens when it is off?" from your actual code saves more time here than another dashboard does.
What we would skip
Skip blue-green for everything if your infrastructure bill is already a conversation. Skip canaries on services with almost no traffic. Skip any rollout tooling that nobody on the team can debug at 3 a.m.
The real problem is not the strategy you pick. It is the gap between shipping code and knowing what it does in production. Progressive delivery shrinks that gap one slice of traffic at a time, and the first slice is the one that matters: make it small, make it observable, and give it an off switch.