What is a feature flag? A practical guide

Feature flags let you ship code switched off and turn it on without a deploy. How they work, the four kinds of flags, and the mistakes to avoid.

4 min read

A feature flag (also called a feature toggle or feature switch) is a condition in your code that decides, at runtime, whether a piece of functionality is on or off. The code is deployed either way; the flag decides who sees it.

if (flags.isEnabled('new-checkout', { userId: user.id })) {
  return renderNewCheckout()
}
return renderOldCheckout()

That small if changes how a team releases software. Deploying code and releasing a feature become two separate decisions: engineers merge and deploy whenever the code is ready, and the feature is released later, to some users or all of them, by changing the flag instead of the code.

Why teams use feature flags

  • Smaller, safer releases. Unfinished work can be merged to the main branch behind a flag that is off, so long-lived branches and painful merges go away.
  • Instant rollback. If the new checkout breaks, switching the flag off takes seconds. No revert, no rebuild, no redeploy.
  • Gradual rollouts. Turn a feature on for 1% of users, watch errors and metrics, then 10%, 50%, 100%.
  • Targeting. Show a feature only to internal staff, beta testers, one country or one customer plan.
  • Experiments. Split users between two versions and measure which one performs better.

The four kinds of flags

The most useful way to think about flags comes from Pete Hodgson's article Feature Toggles (aka Feature Flags) on martinfowler.com. It groups flags by how long they live and how often they change:

Kind Purpose Lifetime
Release flags Hide unfinished or unreleased work Days to weeks, then removed
Experiment flags A/B tests and multivariate experiments As long as the experiment runs
Ops flags Kill switches and load shedding for risky parts of the system Some short, some permanent
Permission flags Features for specific users, plans or regions Often permanent

The distinction matters because each kind needs different handling. A release flag that is still in the code six months after launch is technical debt. A permission flag that controls a paid plan is part of the product.

How a flag is evaluated

Every flag system has the same three parts:

  1. A definition: the flag's key, its possible values (on/off, or variants like "A", "B"), and its rules.
  2. A context: what is known about the current request, such as user ID, email, country, plan or app version.
  3. An evaluation: the rules applied to the context, producing a value.

A rule set might read: on for anyone whose email ends in @yourcompany.com; on for 20% of everyone else; off otherwise. The percentage part uses a hash of the user ID so the same user always lands in the same group. See how percentage rollouts work for the details.

Where the evaluation happens matters too. Server-side SDKs usually download all the rules and evaluate locally, so checking a flag costs microseconds and keeps working if the flag service goes down. Client-side SDKs (browser, mobile) usually receive only the already-evaluated values for the current user, so your rules and other users' data are not exposed.

Build or buy?

A boolean in a config file is a feature flag, and for a small team it may be enough. You outgrow it when you need any of these:

  • changing a flag without a deploy;
  • percentage rollouts and user targeting;
  • an audit log of who changed what and when;
  • different values per environment (development, staging, production);
  • non-engineers changing flags safely.

At that point most teams adopt a dedicated tool, either hosted or open source and self-hosted. The OpenFeature project, part of the CNCF, defines a vendor-neutral API for evaluating flags, so your code is not locked to one provider.

Common mistakes

  • Never removing flags. Every flag doubles the number of paths through the code. Plan the removal when you create the flag. See how to find and remove stale flags.
  • Nesting flags. A flag that only matters when another flag is on creates combinations nobody tests.
  • Testing only the "on" path. Until the flag is removed, both paths are production code.
  • Using flags for configuration. A timeout or a price is configuration, not a flag. See feature flags vs. configuration vs. environment variables.
  • Evaluating on the client what must stay private. Rules sent to a browser can be read by anyone.

Summary

A feature flag separates deploying code from releasing it. Used well, it makes releases smaller, rollbacks instant and experiments cheap. Used carelessly, it leaves the code full of dead branches. The difference is discipline: name flags clearly, give each one an owner and a removal date, and clean up after launch.