← Blog

Progressive delivery: the strategy behind staged rollouts

Progressive delivery is the practice of releasing a change to a small slice of users or traffic first, checking a metric, then widening the rollout in stages instead of shipping to everyone at once. It covers canary releases, ring deployments, and percentage-based feature flag rollouts, all built on the same move: ship the code, then release it gradually and reversibly.

The strategy exists because of one recurring failure: a change passes every pre-release check and still breaks for a reason only real production traffic reveals, like a dependency that chokes under concurrency or a query plan that degrades at live data volume. Shipping to 100% at once means every user hits that failure at the same time. Progressive delivery means ten of them do, first.

This post covers the stages of a progressive delivery strategy and where a feature flag sits underneath the rollout curve.

Key Takeaways

  • Progressive delivery widens exposure in stages (often 5%, 25%, 50%, 100%), checking a guardrail metric before each step, instead of a single all-at-once release.
  • It spans three mechanisms: canary release (infrastructure-level traffic shifting), ring deployment (grouped cohorts like internal, beta, GA), and feature flag rollouts (code-level, per-user).
  • A feature flag is the only one of the three that controls exposure without a new deploy at each stage. In dif, widening a rollout means editing a weight in a Markdown file and merging.
  • The guardrail metric is the part that makes the strategy work. Without one worth trusting at each stage, a staged rollout is just a slower all-at-once release with extra steps.

The stages: 5%, 25%, 50%, 100%

A typical progressive delivery curve has four stages, though the exact percentages vary by team and by how reversible the change is. Each stage holds until a guardrail metric (error rate, p99 latency, or a business metric like completed checkout) confirms the new version is not regressing, then widens.

5% catches the failure that only shows up under real concurrency or real data, the kind no staging environment reproduces. 25% catches a failure that needed more volume to surface, like a rare input combination. 50% and 100% mostly confirm the metric holds at scale, since most real breakage already showed up earlier.

The stages are a dial, not a sequence of separate releases. Widening from 25% to 50% should not require re-deploying or re-testing the change itself, only changing who is exposed to code that is already live.

Three mechanisms, one strategy

Progressive delivery is not one tool. It is a strategy that three different mechanisms can implement, each operating at a different layer.

Canary release operates at the infrastructure layer. A percentage of traffic routes to a new set of instances or pods running the new build, while the rest keeps hitting the old one. Rollback means draining traffic back to the old instances.

Ring deployment operates at the cohort layer. Internal employees get the change first, then a beta group, then general availability, each ring a fixed group rather than a shifting percentage. Microsoft’s update rings for Windows are the canonical example of rings in production.

Feature flag rollout operates at the code layer. The build is the same everywhere; a flag decides, per user, whether a given code path runs. Feature flags are the mechanism that needs no new deploy to widen a stage, because the weight that controls exposure lives in the flag, not in which binary is running.

These can run independently or stacked. A canary at the infrastructure level and a flag at the code level answer different questions: which instances are running the new binary, and which users, on any instance, see the new path turned on.

Where a staged rollout breaks

The guardrail metric is the single point of failure for the whole strategy. A metric that takes a day to move lets a bad stage sit at 5% for 24 hours before anyone notices. A metric too noisy to trust either blocks releases that are fine or waves through ones that are not.

A second failure mode is treating the stages as fixed percentages regardless of blast radius. A change to a payment path and a change to a tooltip’s copy do not deserve the same curve. The payment path needs a slower ramp and a faster kill; the tooltip can move through 5% to 100% in an afternoon.

A third: conflating the rollout mechanism with the rollback mechanism. Canary and ring deployments roll back by shifting traffic or by rolling the cohort back, which is fast, often seconds. A feature flag’s rollback in a git-native tool is a commit and, depending on the pipeline, a deploy. That is slower by design, because every change to the flag is reviewed.

Progressive delivery as a feature flag file

In dif, a staged rollout is one Markdown file, and each stage is an edit to the weight field:

---
id: new-search-ranking
status: active
owner: team@example.com
surface: search
variants:
  - id: "off"
    weight: 95
  - id: "on"
    weight: 5
---

Widening from 5% to 25% means changing weight: 95 / weight: 5 to weight: 75 / weight: 25 and merging the pull request. dif validate checks the weights sum to 100 and the owner is a real email before the change reaches CI, so a malformed stage fails the build instead of reaching production. The history of every stage, who approved it and when, is the git history, not a dashboard’s audit log that can drift from what the code actually does.

The tradeoff: a commit is not a switch

A canary’s traffic shift and a ring’s cohort swap both revert in the time it takes infrastructure to update, typically seconds, with no new build. A flag’s rollback is editing a number to 0, merging, and running the pipeline. If a build takes ten minutes, that is the worst-case kill time for a flag-driven stage.

For a payment path that needs a sub-second kill switch, the router-level control canary and ring deployments give is the right tool, not a flag. For most features, where the failure mode is “some users see something wrong” rather than “the site is down,” the slower, reviewed rollback is worth it. Every stage has a reason attached in the commit history instead of in someone’s memory of a dashboard toggle.

FAQ

What is progressive delivery? Progressive delivery is releasing a change to a small percentage of users first, checking a metric, then widening in stages until it reaches everyone. It includes canary releases, ring deployments, and feature flag rollouts.

What is the difference between progressive delivery and continuous delivery? Continuous delivery is about shipping code to production quickly and reliably. Progressive delivery is about controlling who is exposed to that code once it is there. A change can be continuously delivered and still roll out progressively to users.

What is the difference between a canary release and progressive delivery? A canary release is one mechanism for doing progressive delivery, operating at the infrastructure layer by routing a percentage of traffic to new instances. Progressive delivery is the broader strategy, which also includes ring deployments and feature flag rollouts.

Do feature flags do progressive delivery? Yes. A feature flag’s weight controls what percentage of users see a code path, and widening a stage means editing that weight, with no new deploy required to change exposure.

What percentage should the first stage of a rollout be? There’s no universal number, but 1-5% is common for the first stage, enough to surface a real-traffic failure without exposing most users to it. A higher-risk change (a payment path) warrants a smaller first stage and a slower ramp than a low-risk one (a UI tweak).

How long should each stage hold before widening? Long enough for the guardrail metric to be trustworthy at that volume, not a fixed clock time. A metric that needs a day of data to be meaningful means the stage holds for a day, regardless of how good it looks after an hour.

Getting started

Progressive delivery is the practice of widening exposure in stages, gated on a metric, instead of shipping to everyone at once. Canary releases and ring deployments do this at the infrastructure and cohort layer. A feature flag does it at the code layer, and it’s the only one of the three where widening a stage is an edit to a file instead of a new deploy.

Install the CLI and scaffold a flag to try a staged rollout:

npm install -g @dif.sh/cli
dif init

See the feature flags landing page for the full model, or the docs for the install and the file format.