Tags: web-dev experimentation concept

Feature Flags

Date: 2026-08-16


A runtime conditional that separates deploying code from releasing behaviour. It’s the practice that makes everything else here possible — gradual rollout, instant rollback, experimentation, trunk-based development — and the debt it creates is real and rarely paid.


What it is

A feature flag is a check evaluated at runtime that decides whether a code path is active, configurable without a deploy.

if (flags.isEnabled('new-checkout-flow', user)) {
  return <NewCheckout />;
}
return <LegacyCheckout />;

The consequence is the whole point: code can ship to production switched off. Deployment becomes a low-risk technical event; release becomes a separate business decision, made later, by someone else, reversibly.

The four kinds

They have different lifespans and mixing them up is the usual source of flag debt.

KindPurposeLifespan
ReleaseShip incomplete work off, enable when readyDays to weeks — remove after
ExperimentAssign variants for a testThe test’s duration — Rollouts as Experiments
OperationalKill switch for an expensive or fragile featureLong-lived, deliberately
PermissionEntitlement by plan, role or regionPermanent — arguably not a flag at all

Only the first two are temporary, and only the first two get cleaned up — in theory. Recording the kind at creation is what makes cleanup possible later.

What it unlocks

  • Progressive Delivery — 1%, 5%, 25%, 100%, watching guardrails between steps
  • Instant rollback. Turning a flag off is seconds; redeploying is minutes and carries its own risk — Rollback and Forward Fix
  • trunk-based development — merge unfinished work behind a flag rather than maintaining a long-lived branch
  • Experimentation. The same machinery assigns variants — though a flag rollout is not an experiment unless a comparison group is held back concurrently, see Rollouts as Experiments
  • Decoupled release timing. Marketing launches when the campaign is ready, not when the deploy window is

The debt

Every flag is a branch in the code, and branches multiply.

3 flags   →  8 possible states
10 flags  →  1,024
20 flags  →  over a million combinations, none of which are tested

Consequences that show up within a year: untestable combinations, dead code nobody dares delete, if statements whose original purpose is unrecorded, and flags left permanently on that nobody realises are still evaluated.

The discipline that works:

  • Record an owner and an expiry date at creation. A flag without both is technical debt on day one
  • Remove the flag as part of finishing the feature, not as a follow-up ticket. Follow-up tickets don’t happen
  • Alert on stale flags — anything past its expiry date, or fully rolled out for a month
  • Cap the number of active flags and treat exceeding it as a blocker
  • Default to off. A flag whose default is on isn’t protecting anything

Implementation

Decisions that matter more than the vendor choice:

  • Where it’s evaluated. Server-side avoids the flicker and blocking problems of client-side entirely — Client-Side vs Server-Side Testing, Flicker and Flash of Original Content
  • What happens on failure. If the flag service is unreachable, the answer must be a safe local default, not an exception and not “on”. A flag service that can take down the site has inverted its purpose
  • Latency. Evaluation must be local and synchronous after an initial fetch. A network call per flag check is unusable
  • Consistency. The same user must get the same answer across page loads and across services — deterministic hashing rather than stored state — Assignment and Bucketing
  • Auditability. Who turned what on, when. This is the first question after an incident

Where it bites

  • Flags in the data layer or analytics. Not recording which flags a user had makes any behavioural analysis unreadable — Experiment Assignment Tracking
  • Flags controlling database schema. They don’t. Schema changes need their own approach — Database Migrations
  • Flags as configuration. Anything that varies permanently by environment is config, not a flag
  • Testing. CI should test the state you intend to ship, and at minimum both states of any flag currently mid-rollout