Cloud and infrastructure as code
Feature flags
A feature flag picks a code path at runtime. It lets you deploy code dark, ramp it safely and separate deploy from release. Keep flags short-lived, because stale flags are production hazards.
A feature flag is a runtime switch that chooses a code path without shipping a new artifact. It separates two events. A deploy puts the code on servers. A release makes the change visible to users. Flags let you do the first without doing the second.
The four kinds
Pete Hodgson's taxonomy on martinfowler.com still describes how teams use flags.
| Kind | Lifetime | Owner | Example |
|---|---|---|---|
| Release | Days to weeks | Engineering | Hide a half-finished checkout rewrite |
| Ops | Months to years | Engineering or SRE | Kill switch for an expensive recommendation call |
| Experiment | Days to weeks | Product and data | 5% of users see new onboarding |
| Permissioning | Years | Product | Enterprise tier gets SSO |
Release flags let you merge and deploy continuously while the feature stays dark. Ops flags are circuit breakers you can flip faster than a rollback. Experiment flags need consistent bucketing and analytics. Permissioning flags are really product data, so treat them as durable configuration, not temporary toggles.
Walking through a ramp
The code path is a single branch.
if (await flags.isEnabled("checkout-v2", { key: user.id, plan: user.plan })) {
return renderCheckoutV2(req);
}
return renderCheckoutV1(req);Here is a safe ramp for checkout-v2. The flag starts at 0%, so the deploy changes nothing for users. Turn it on for 1% of users in one region. Watch the golden signals for 30 minutes. Then go to 10%, 50% and 100%. If p99 latency doubles at 10%, turn the flag off in seconds, with no container rollback.
When the flag has been at 100% for a week, delete the old code path and the flag in the same change. That last step is mandatory.
OpenFeature is a vendor-neutral API. Application code calls it, and the provider behind it can be LaunchDarkly, Unleash, Flagsmith or your own Redis hash. The if (flag) call sites stay the same when the provider changes.
Flag debt
Every flag is a fork in the code. Five uncoordinated flags make a combinatorial space that nobody tests. Keep the debt small.
- Name each flag with its purpose and expiry, such as
checkout_v2_release_2026q2. - Track flags on the backlog, and alert when a release flag is older than an agreed number of days.
- Use short-lived release flags, and never reuse an old flag for a new purpose.
- Test both sides of critical flags, or at least the default off path.
Warning
Knight Capital Group lost roughly $440 million in 45 minutes in 2012. A deploy reused an old flag, which activated obsolete dead code on production servers. The takeaway is that flags are production control surfaces, and stale ones are landmines. Remove them when the release is done.
Common mistakes
- Leaving release flags in place forever. Each one is an untested branch.
- Defaulting a flag to on in production config. A new deploy then ships the feature to everyone at once.
- Reusing a flag name. Old code may still be wired to it.
Check yourself
- A release flag has been at 100% for a week. What should you do? Answer: Delete the old code path and the flag together, in one change.
- Why is reusing an old flag dangerous? Answer: Old code can still respond to it, which is how Knight Capital activated dead code in 2012.
Key takeaways
- A flag separates deploy from release, and chooses a code path at runtime.
- Use the four kinds, and give each one an owner and an expiry.
- Ramp in small steps, and watch the golden signals at each one.
- Delete flags when the release is done. Stale flags are a risk.
Further learning
Pete Hodgson's article on feature toggles is the source of the taxonomy above.
Feature Toggles (Pete Hodgson, martinfowler.com)Feature Toggles (aka Feature Flags)martinfowler.comA practical talk on using flags to raise deploy frequency and separate release from rollout.
OpenFeature and LaunchDarkly: What are feature flags? cover the API standard and the product side.
Next, see the risk of changing the flags and settings that are read live: dynamic config and blast radius.
Related
Configuration, environments and feature flags
Twelve-factor config, environment parity, secrets injection, feature flags and the blast radius of a bad config push.
A/B testing and experimentation
Designing randomized experiments, sizing samples with real arithmetic, reading lift and confidence intervals, and shipping only what the data actually supports.
Metrics, dashboards and alerting
Golden signals, RED and USE, Prometheus histograms and alerts that page you only when users are hurting.