Feature Flag

A feature flag is a conditional that decides at run time whether a piece of behaviour is active, so that code can be deployed without the feature being visible. The terms are interchangeable: “feature toggles are also refered to as feature flags, feature bits, or feature flippers. These are all synonyms for the same set of techniques.”

Its central use is one sentence: release toggles “allow incomplete and un-tested codepaths to be shipped to production as latent code which may never be turned on,” which is “the most common way to implement the Continuous Delivery principle of ‘separating [feature] release from deployment.'" That separation is what lets a team integrate daily while a feature takes three weeks to finish.

Four kinds, and why the difference matters

"Feature flag" names four things that need managing differently, because they differ on two axes — how long they live, and how fast the decision has to change.

KindPurposeLifetimeHow dynamic
ReleaseShip unfinished code dark, turn it on when ready"Transitionary by nature… not much longer than a week or two""Typically very static" — a redeploy to flip it is acceptable
ExperimentA/B or multivariate testing, users assigned to cohorts"Long enough to generate statistically significant results"; longer risks other changes invalidating the result"Highly dynamic" — per user
OpsDisable or degrade behaviour operationally; kill switchesShort for a new feature; a few key controls stay "almost indefinitely"Must be changeable "extremely quickly" — a redeploy is too slow
PermissioningEntitlements — premium, alpha, betaFor premium features, "at the scale of multiple years""Always be per-request, making this a very dynamic toggle"

Read the last two columns together and the management rules fall out. A release toggle can live in a configuration file the deployment reads, because flipping it by shipping a release is fine. An ops toggle cannot — the whole point is reacting during an incident, and "needing to roll out a new release in order to flip an Ops Toggle is unlikely to make an Operations person happy." A permissioning toggle is evaluated per request against user data, which makes it part of your authorization model rather than part of your delivery process.

Mixing the categories is the most common way a flag system becomes unmanageable. A release toggle that outlives its two-week window has stopped being a delivery tool and become a permanent branch in the code — one that nobody will remove, because nobody can now say which state is correct.

The long-lived operational exception is legitimate and worth naming as such: a kill switch allows "operators of production environments to gracefully degrade non-vital system functionality when the system is enduring unusually high load," and the published reading is that such a toggle "could be seen as a manually-managed Circuit Breaker." Which is a good way to think about it — the same protective idea as automatic throttling, deliberately kept under a human's hand.

What it costs

Flags are cheap to add, which is the problem: "toggles do come with a carrying cost. They require you to introduce new abstractions or conditional logic into your code. They also introduce a significant testing burden."

The testing burden is structural, not a discipline problem. Since a deployed artifact can be flipped either way in production, "in order to validate all codepaths which may end up live in production we must perform test our artifact in both states: with the toggle flipped On and flipped Off" — and "with multiple toggles in play we have a combinatoric explosion of possible toggle states."

You cannot test every combination, so the practical move is to decide which combinations are real — normally the configuration currently in production and the one you are moving to — and write that decision down. A team that has not made it explicitly has made it implicitly, by testing whichever state the test environment happened to have.

Flags are inventory. "Savvy teams view the Feature Toggles in their codebase as inventory which comes with a carrying cost and seek to keep that inventory as low as possible." Published tactics all work by forcing removal rather than relying on intention: adding a removal task to the backlog the moment a release toggle is created, putting expiration dates on toggles, or going as far as "time bombs" that fail a test — or refuse to start the application — once a flag has outlived its window. The cautionary example cited is Knight Capital, which is a reminder that stale flag state can be expensive rather than merely untidy.

Three decisions to make before the first flag

  1. Who can change it, and how fast. This follows from the category. Getting it wrong in the safe direction — an ops toggle that needs a deployment — means the control is useless in the incident it was built for.
  2. Where the current state is visible. During an incident, "which flags are on right now" has to be answerable in seconds, because flag state is part of what version of the system is running.
  3. When it gets deleted, and whose task that is. Named at creation, with a date. Everything else is how codebases end up with flags whose purpose has been forgotten and whose removal nobody dares attempt.

One placement note: not every flag belongs at the edge. Lower-level toggles "must be placed deeper within your architecture," and "localizing these toggling decisions within the service whose functionality is being toggled is the only sensible option in these cases" — for example a toggle choosing whether to route through a new cache.

Finally, keep gradual exposure by flag distinct from gradual exposure by deployment. Turning a feature on for internal or beta users first is a different thing from a canary deployment: "a Canary Released feature is exposed to a randomly selected cohort of users while a Champagne Brunch feature is exposed to a specific set of users." Both are useful, and the difference is what each licenses you to conclude rather than which one counts as a canary. Exposing a hand-picked group first is a perfectly ordinary way to watch for breakage — one region, internal users, a few consenting customers. Where it fails is as a comparison against everyone else, because whatever made those users selectable may also explain the difference you measure. That is a limit on how the group was chosen, though, and it does not rule out experimenting inside the group: randomly assigning old and new versions within a pre-selected set of consenting customers is an ordinary controlled experiment, and it estimates the effect for that set. What the selection costs is the right to generalize the number to everybody. Random assignment is what supports the causal reading; it is not what makes the exposure gradual, and on its own it does not make the observation informative either, since a cohort that is too small, observed at an off-peak hour, or whose two arms interfere with each other tells you little whatever its sampling. How flags combine with progressive deployment and with schema compatibility is worked through in Two Versions at Once, and flags are what make daily integration compatible with unfinished work — the mechanism behind small batches.

Reference: Pete Hodgson, Feature Toggles (aka Feature Flags), martinfowler.com; NIST/SEMATECH e-Handbook, Completely randomized designs (both checked September 2026).


Discover more from Insightful Data Lab

Subscribe to get the latest posts sent to your email.

Similar Posts

Questions, corrections, or additional insights?

This site uses Akismet to reduce spam. Learn how your comment data is processed.