THIS EXPLANATION
THE ROOM
CDA·93 Computing, Data & AI 6 MIN · 8 STATIONS

Feature flags

A Socratic walk-through of feature flags — reasoned out one step at a time, not lectured.

abcdefgh
a

The question we started with

THE QUESTION #

Why ship code to production that you have deliberately arranged not to run?

Here is a practice that looks, at first, like deliberate waste. A team writes a new checkout flow, tests it, merges it, and ships it to production — wrapped in a condition that evaluates to false, so that not one customer can reach it. The code is there. It is compiled, deployed, running on every server. It simply does nothing.

Why would anyone pay to ship something they have arranged not to run? The intuitive answer is caution, and that is nearly right but not precise enough to be useful. What is worth asking instead is: what exactly did the team gain at the moment the dead code landed on the servers, before anyone flipped anything?

b

Reasoning it through

REASONING #

Start with what happens without the flag. The new checkout lives on a branch. It cannot go to production until it is finished, so the branch stays open for three weeks while the rest of the codebase moves underneath it. Every day the merge gets a little harder. And when it finally lands, it lands all at once: a large, unfamiliar change arriving in production in a single event.

Now ask what makes that event frightening. Not the size of the diff exactly — rather that two distinct things happen simultaneously. New code begins executing on the servers, and customers begin experiencing new behaviour. If something goes wrong, you cannot tell which of those two facts is the cause, and the only remedy available is to undo both together by rolling the deployment back.

Notice what a flag does to that. It separates the two events in time. Shipping the code becomes one action; letting a customer reach it becomes another, taken later, by a different mechanism. That separation is the entire idea, and the industry's name for it — decoupling deploy from release — says exactly that. A deploy moves bits onto machines. A release exposes behaviour to people. They were only ever welded together by accident.

What does the separation buy? Consider the diagnostic value first. When the code has been sitting in production for a week doing nothing and you then enable it for one percent of traffic and errors appear, you have learned something quite specific: the failure is in the new path, not in the deployment. You have isolated a variable, which is the same move an experimenter makes for the same reason.

Then consider the speed of undoing. Rolling back a deployment means moving artefacts, restarting processes, and hoping nothing in between has migrated forward. Flipping a flag means changing a value that the running process reads — typically taking effect in seconds, without a restart. When a bad change is live, the difference between a minute and twenty minutes is not a convenience; it is most of the damage.

And there is a third gain, easy to miss because it is about people rather than machines. If the half-finished feature can live safely in the main branch behind a false condition, nobody needs a long-lived branch. Work integrates continuously, in small pieces, each individually reviewable. The flag is what makes trunk-based development possible for work that takes longer than a day.

So the dead code was never the point. The point was the option — the ability to decide later, quickly, and independently, who sees the new thing. Shipping it dark is simply the price of holding that option.

Which raises the obvious counter-question: if flags are so useful, why not flag everything? Here the honest answer is that each flag is a branch in the code, and n independent flags describe two-to-the-n possible configurations, only a handful of which anyone will ever test. That combinatorial growth is the real cost, and it is why the discipline that matters most is not adding flags but removing them.

c

The analogy

THE ANALOGY #
THE FIGURE

Think of a new wing built onto a hospital, finished, furnished, wired, inspected — with the connecting doors locked. The building work is entirely done and the disruption of construction is over. The decision to admit patients is now a separate, small, reversible act: unlock one door, admit one ward's worth of people, watch. If something is wrong with the ventilation, you lock the door again in a moment. You do not demolish the wing.

WHERE IT BREAKS DOWN

an unopened hospital wing costs nothing to leave standing, whereas a disabled code path is inside a living system — it is compiled, it can be reached by a bug, it interacts with the code around it, and left in place long enough it becomes a piece of accumulated complexity that nobody dares delete.

d

Clarifying the model

THE MODEL #

Three refinements to the picture.

First, the flags people call by that one name are doing several different jobs, and conflating them causes trouble. A release flag exists to be removed within weeks of the feature going to everyone. An experiment flag exists to split traffic for a measurement and dies when the measurement concludes. An operational flag — a kill switch on an expensive recommendation service — is meant to live indefinitely. A permission flag encodes who is entitled to a feature and is really product configuration, not a release tool. Only the first two carry a debt to be paid off; treating all four alike is why teams end up with hundreds of stale toggles.

Second, a flag is not a substitute for testing. A false condition guarantees the path is not taken, not that the path is correct, and the moment you enable it you are testing in production whether you meant to be or not. The flag makes the blast radius small and the retreat fast; it does nothing about whether the code works.

Third, the failure mode worth naming out loud: the 2012 Knight Capital incident, in which a firm lost roughly $440 million in about 45 minutes, hinged partly on a flag reused for a new purpose while old code that still responded to it remained on one of eight servers. Reused flags, half-removed flags, and flags whose meaning has drifted are not a hypothetical hazard. Removal is part of the practice, not a tidy-up afterwards.

e

A picture of it

THE PICTURE #
Feature flags
Feature flags Read left to right as elapsed time, and note that only the first stop is a deployment -- every later stop is a configuration change to code that is already running. The interesting property is that you can move backwards between any two middle stops in seconds. The last stop is the one teams skip; it is what stops the second column of stages from accumulating forever. {"generator":"[email protected]","source":"../Socrates/.diagram-cache/_src/feature-flags.md","sourceIndex":1,"sourceLine":4,"sourceHash":"be0050e40d307573cbe46386585d8eb97d4f3983f00715da424409978c835c54","diagramType":"timeline","layoutVariant":"source","repairedDuplicateIds":[],"motion":"entrance-with-reduced-motion-fallback","presentation":"editorial","attempt":1,"viewBox":{"x":0,"y":0,"width":1554,"height":548},"qa":{"passed":true,"findings":[]}} Merged dark Flag added,defaults off Code on everyserver, unreachable Internal only Enabled for staff First real traffic,cheap to fix Small share One percent ofusers Errors now isolateto the new path Ramped up Widened as metricshold Kill switch still onevalue away Fully on Old path no longerserved Flag removed Condition and deadbranch deleted Debt paid

How to readRead left to right as elapsed time, and note that only the first stop is a deployment — every later stop is a configuration change to code that is already running. The interesting property is that you can move backwards between any two middle stops in seconds. The last stop is the one teams skip; it is what stops the second column of stages from accumulating forever.

f

What became clearer

WHAT CLEARED #
WHAT CLEARED

A feature flag is not a safety net draped over a risky change. It is a way of splitting one irreversible event into two independent ones — putting code on servers, and putting behaviour in front of people — so that each can be timed, sized, and undone on its own. The dead code in production is what that option costs, and the flag left behind after the feature is universal is what it costs when the option is never closed out.

g

Where to go next

ONWARD #
  • Canary releases and staged rollouts, which are what the flag's middle stages are actually doing.
  • Trunk-based development, and why long-lived branches and flags solve overlapping problems differently.
  • How teams inventory and expire flags automatically, so removal is not left to memory.
h

Key terms

TERMS #
TermWhat it means
Deploy/release decouplingtreating "code is on the servers" and "behaviour is visible to users" as two separately controlled events.
Kill switchan operational flag kept indefinitely so an expensive or fragile subsystem can be turned off under load.
Trunk-based developmentintegrating small changes into a single main branch continuously, rather than maintaining long-lived feature branches.

Every term the collection defines is gathered in the glossary.

Nearby on the shelf

4