The code has been in production for three weeks. Nobody has seen it.
That is not a bug — that is the point. A feature flag splits one frightening event into two ordinary ones: deploying, a technical act you should do constantly, and releasing, a business decision you should be able to reverse in seconds. Deploy ≠ release.
Commit before you look.
A risky checkout rewrite has sat in production behind a flag, switched off, for three weeks. You flip it on for everyone at once and it immediately falls over. The bug shipped anyway. So what did the flag actually buy you?
Ship the same broken change two ways.
The change is identical and the bug is identical. All that differs is whether the deploy is the release. Pick a mode, choose how much of your traffic sees the new path, and ship it. Each square is one percent of a week's users.
One hundred squares, one week of traffic. Lit squares are the share of users routed to the new code path.
Stops at 0, 1, 5, 25, 50 and 100 %. With deploy = release there is no dial to turn: everyone gets it the moment it lands.
Every flag you keep doubles the software you own.
A flag is a permanent if statement in your production system, and two flags
make four possible configurations, three make eight. Your test suite exercises one of them. Drag the
count and watch what you are actually shipping — then look at the ages.
Two events that most teams have welded together.
The whole idea is one separation. Once deploying and releasing are different events, almost every property of shipping software changes — including who gets to decide.
| Deploying | Releasing | |
|---|---|---|
| What it is | Code reaches a production server. | A user is routed to that code. |
| Who decides | Engineering, continuously. | Product — and it can wait for the campaign. |
| How to undo | Build, redeploy, verify. Tens of minutes. | Change one value. Seconds. |
| Blast radius | Whoever the deploy reaches — usually everyone. | Exactly the cohort you chose. |
| Frequency | Should be boring and constant. | Whenever the business is ready. |
| Failure feels like | An incident with a rollback. | A decision you reversed. |
What a flag does not do
It does not make your change less likely to be broken. The defect rate is exactly what it was. A flag attacks the other two terms in the damage equation — how many people were exposed and how long it lasted — and it converts recovery from an engineering exercise into a configuration change. Confusing "smaller consequences" with "lower probability" is how teams end up at option D: testing less because they can always switch it back.
The trade nobody mentions: small blast radius costs you signal
At 1 % exposure the error shows up as three data points in a noisy graph, so it takes minutes to become visible instead of seconds. That is a real cost, not a rounding error — and it is why a canary needs an alert on the cohort, not just a smaller cohort. Compare the numbers at 1 % and 50 % in the console above: the total damage still falls, but detection genuinely gets worse.
Why this is the answer to "but my feature isn't finished"
That objection is the single biggest reason teams keep work on long-lived branches — and a flag is what answers it. Merge the unfinished code to trunk, keep it dark, and integrate every day anyway. Branch Lifetime covers what those long branches cost you in the meantime.
Four flags, four very different weeks.
Flags earn their keep in situations that look nothing alike — and they cost you in one that always looks the same.
A month of production evidence
A new search backend runs on every real query for a month. Its results are thrown away and compared against the old system's; nobody ever sees them. By release day the team has a month of real traffic, real data shapes and real latency numbers — and the release itself is a configuration change.
The Friday kill switch
A payment provider starts degrading at 18:05 on a Friday. One flag falls back to the previous provider in about twenty seconds. The alternative — an out-of-hours rollback — means paging four people, rebuilding, redeploying and verifying, with the checkout down throughout.
1% → 5% → 25% → 100%
The rewrite goes to internal staff, then one percent of customers, then a quarter, then everyone — each step held long enough for the error rate and the latency to settle. Nothing about the code changes between steps. What changes is how much you know before the next one.
The flag graveyard
Two years of "temporary" flags nobody removed. A stale one defaults to on in a newly launched region and resurrects a feature that was retired eighteen months ago — in front of customers who have never seen it. Nobody can say which flag did it, because nobody owns any of them.
Ship the code, then choose who sees it.
Flags are cheap to add and expensive to keep, which is exactly the wrong shape for human incentives — so the discipline is not "use flags", it is "retire them". That is the work we do with the engineering teams we coach: separating deploy from release, drilling the kill switch, and putting an expiry date on every flag before it becomes somebody's Tuesday.
Talk to us about coachingDeploy constantly, release deliberately
Deploying should be so frequent it is boring. Releasing should be a decision somebody makes, on purpose, and can unmake in seconds without an engineer.
Flags cut exposure and time, not probability
The bug is exactly as likely as it was. What changes is how many people meet it and how fast you can stop it — which is most of what "safe" means in practice.
A flag is debt with a deadline
Every live flag doubles the configurations your system can be in, and your suite tests one of them. The release is not done until the flag is deleted.