Feature Flags

What Is a Feature Flag? The Complete Guide for Product Teams

What is a feature flag? Learn the 4 flag types, safe rollout strategies, and how to avoid feature flag technical debt in your product.

Abstract illustration of overlapping geometric switches and panels in dark green and teal, representing gradual activation and controlled feature release

A feature flag is a switch in your code that separates the moment a change reaches production from the moment it actually reaches users. This guide covers the concept from the ground up: the four types of flags, how to run a safe progressive rollout, a neutral comparison of LaunchDarkly, Unleash, Flagsmith, PostHog, and Statsig, and the technical debt risks nobody mentions when they pitch the idea. If you landed here specifically looking for the difference between a feature flag and an A/B test, or whether to evaluate a flag on the client or the server, see our dedicated guides on feature flags vs A/B testing and client-side vs server-side testing.

What a feature flag is, in plain terms

A feature flag (also called a feature toggle, or just a flag) is a conditional structure in your code, usually a boolean or a targeting rule, that decides at runtime whether a given code path executes. In its simplest form, it looks like this:

if flag("new-checkout") is on for this user, show the new checkout, else show the old one

The term “feature toggles” was popularized in this technical sense by Pete Hodgson in an article published on Martin Fowler’s site, which remains the most commonly cited reference on the topic. The idea it describes is simple to state and powerful in practice: a flag decouples two decisions that, without it, are welded together by the deploy process itself. Without a flag, “the code is in production” and “the feature is available to the user” are the same event, happening at the same instant, decided by whoever presses the deploy button. With a flag, they become two independent decisions: engineering decides when the code ships; product, marketing, or the system itself decides when, and for whom, it turns on.

That separation sounds small on paper, but it changes the temperature of every deploy. Without flags, shipping a new feature is a binary risk event: it either works for everyone, or you scramble to roll back the entire deploy (and whatever else shipped alongside it). With flags, the deploy becomes a low-risk event (the code exists, but it is off, or visible only to a handful of internal accounts) and the release becomes a controlled, gradual, reversible-in-seconds event of its own.

A feature flag is not the same thing as a branch

A common question from teams just adopting flags: “why do I need a flag if I already have Git branches?” The answer is that branches and flags solve problems at different points in the code’s life cycle. A branch exists before integration: while your code sits isolated on a feature branch, it doesn’t affect anyone, but it also isn’t being exercised alongside the rest of the system, and the longer it stays isolated, the more painful the eventual merge becomes (the classic “merge hell” problem). A flag exists after integration: the code is already on the main branch, already running through the same automated tests as everything else, already deployed, and the flag decides whether it is visible.

That property is what underpins trunk-based development: merging directly into the main branch multiple times a day, even with half-finished features, because the flag guarantees that unfinished code stays invisible until it’s ready. Fowler and Hodgson describe this as one of the central uses of feature toggles, allowing teams to keep shipping continuously without waiting for a large feature to be 100% complete before merging it.

Deploy and release as two separate events Without a feature flag, deploy and release to the user happen at the same instant. With a feature flag, code ships turned off, and release to the user happens later, in a controlled way, without requiring a new deploy. Without a feature flag Code is ready Deploy = release same instant Every user sees it binary risk With a feature flag Code is ready Deploy, flag off no one sees it yet Release whenever gradual, reversible
A flag turns deploy into a low-risk event (code present, but invisible) and release into a controlled event, decoupled from the deploy calendar.

Why teams use feature flags

The core motivation is reducing the risk of every production change, and it breaks down into four concrete benefits that show up, under slightly different names, in nearly every serious write-up on the topic, including LaunchDarkly’s and Unleash’s own documentation.

Deploy decoupled from release

As described above: engineering can integrate and ship code as often as it needs to (multiple times a day, for teams practicing mature continuous delivery) without that meaning every change is instantly exposed to the entire audience. This breaks the dangerous link between “how often I deploy” and “how much risk I take on per deploy.”

Instant rollback, no new deploy required

If a new feature causes a problem in production, turning the flag off reverts the behavior in seconds, without opening a new pull request, waiting for the build and test pipeline to run again, and shipping a new deploy under pressure, the single most error-prone situation in engineering. This is, according to LaunchDarkly’s own documentation and the broader continuous delivery literature, one of the biggest operational wins of feature flags: turning an incident that would take minutes or hours to revert into a single click.

Segmented, controlled release

Instead of “everyone sees it or no one does,” a flag lets you decide exactly who sees it: only the internal team, only one specific beta account, only 5% of traffic, only users in one country, only accounts on a specific plan. That granularity is what makes it possible to validate a high-risk feature (a checkout redesign, for example) with minimal exposure before taking on the full risk.

Long-term personalization and permissions

Not every flag is temporary. Some live forever, gating access to a premium feature, a capability available only on a specific plan, or a setting that varies by customer in a multi-tenant product. This category, covered below as permission flags, isn’t about reducing deploy risk; it’s about modeling a business rule.

The four types of feature flag

Not every flag serves the same purpose, and confusing the types is the root of much of the technical debt covered later in this guide. The categorization most commonly cited in the literature, including Hodgson’s article and LaunchDarkly’s documentation, organizes flags along two axes: how long they live (temporary vs. permanent) and who decides the value (a person, a system, or the business logic itself).

The four feature flag types by lifespan and purpose Release and experiment flags are typically short-lived, days to a few weeks. Ops and permission flags tend to live much longer, months or permanently. typical flag lifespan days permanent Release hides code until ready Experiment compares variations with data Ops kill switch circuit breaker operations Permission plan, tier, premium access
Release and experiment flags are born to die young. Ops and permission flags tend to live for weeks, months, or permanently, because they encode an operating rule or a business rule, not a transient delivery state.

Release flags

Hide an incomplete or unvalidated feature until it’s ready for everyone. This is the most basic and most common use: letting engineering merge and deploy work in progress without affecting users. Lifespan: short, days to a few weeks. The flag should be removed as soon as the feature is fully rolled out and stable, which, in practice, rarely happens on schedule (more on that in the risks section below).

Experiment flags

Split traffic between two or more variations to measure the effect of each on a metric, with statistical rigor: calculated sample size, significance, a minimum run time. This is the category that powers A/B testing: every experimentation tool uses flags under the hood to decide which variation each user sees, but not every flag is an experiment. The conceptual difference between the two, and when one turns into the other, is covered in depth in our guide on feature flags vs A/B testing. Lifespan: short and well defined, the duration of the experiment (usually one to a few weeks), ending in a “keep or discard” decision.

Ops flags (operational)

Control the operational behavior of the system in production: a kill switch that turns off a misbehaving third-party integration, a circuit breaker that cuts a call to an unstable downstream service, a load-shedding control that reduces functionality under a traffic spike. Unlike a release flag, the goal here isn’t to hide something unfinished; it’s to give the operations team an emergency button. Lifespan: typically long, sometimes permanent, because the operational risk it mitigates (an unstable dependency, a seasonal spike) doesn’t go away.

Permission flags (entitlements)

Control what a specific user, account, or organization can access, typically gated by subscription plan, role within the account, or a specific contract (a feature unlocked only for one enterprise customer, for example). Unlike the other three categories, this flag isn’t about managing delivery risk; it’s about modeling a business rule, what LaunchDarkly’s own documentation refers to as “entitlements.” Lifespan: permanent, for as long as the plan segmentation exists.

release = hide until ready · experiment = compare with data · ops = emergency button · permission = who can access

Feature flags vs A/B testing: where the line sits

It’s worth clearing up the most common confusion before going further, because it shows up in almost every conversation on this topic: feature flags and A/B testing are not the same thing, and neither is a simplified version of the other.

The flag is the mechanism: a conditional that decides, for a given user, which code path runs. An A/B test is a statistical method that uses that mechanism to answer a specific question: “does variation B convert better than variation A, with enough confidence for me to trust it?” That requires things a plain release flag never needs: stable random assignment of each user to a group, a sample size calculated before the test starts, and a significance test at the end.

Decision tree: is this a feature flag or an A/B test? If you just need to turn a capability on or off for a segment, use a plain feature flag. If you need to compare two variations and decide which one is statistically better, you need an A/B test built on top of flag-style targeting. Do you need to prove which version wins? no, just release control yes, with confidence Plain feature flag on/off or % targeting A/B test sample size + significance release, ops, permission experiment flag + stats engine
Every A/B test relies on flag-style targeting to assign users to a variation, but a plain feature flag never needs a significance test to make its decision.

In practice, that means every A/B experiment uses flags, but most flags in a system (release, ops, and permission, which make up the majority in any mature product) never become a formal experiment. They simply turn a behavior on or off, with no statistics behind them at all. The confusion is common partly because the same tool (LaunchDarkly, Unleash, an A/B testing SaaS like Donnu A/B) frequently offers both capabilities on the same platform, which blurs the line for whoever operates the product day to day.

We cover this boundary in depth, including when a plain release flag should graduate into a real experiment and what changes in the implementation, in our dedicated guide feature flags vs A/B testing.

Client-side vs server-side: where the flag decision happens

Another architecture decision that comes up early in any feature flag adoption is where the code evaluates the flag: in the user’s browser or app (client-side) or in your backend (server-side). It isn’t just an implementation detail; it carries real implications for security, performance, and complexity.

Client-side is simpler to install (a JavaScript SDK, for example) and is the common choice for marketing, onboarding, and interface changes. The cost: the flag logic (in naive implementations, even the values of flags that are off) travels inside the bundle that reaches the user’s browser, which is unacceptable for sensitive business rules or data that shouldn’t leak to anyone without the flag enabled.

Server-side keeps the decision entirely in your backend: the client never sees the code or the values of flags that don’t apply to it, which is the recommended default for permissions, private data, and any logic that shouldn’t be inspectable by opening the browser’s DevTools. The cost is one extra network call (or a periodic configuration sync) and one more piece of infrastructure to keep running.

Mature teams typically use both, each where it makes sense: client-side for what’s visual and low risk, server-side for what’s sensitive or gates access. The full comparison, including the architecture of each approach, typical latency, and how vendors solve the “flicker” problem (the page briefly showing the wrong version before the flag applies), lives in our guide client-side vs server-side A/B testing, which covers the same dichotomy applied to experimentation.

Progressive rollout and canary release

A progressive rollout is the technique of releasing a feature to a growing slice of the audience instead of flipping from 0% to 100% at once. This is where a release flag delivers the most practical value, because it turns “will this work in production?” from a question you can only answer after the fact into a question you answer gradually, with real data and controlled exposure.

Progressive rollout curve over time A typical progressive rollout starts at a small fraction of traffic, such as 1%, climbs to 5%, then 25%, then 50%, and only then reaches 100%, checking health metrics between each step. % of traffic exposed rollout stages 1% 5% 25% 50% 100%
Each step stays live long enough to observe health metrics (errors, latency, business guardrails) before advancing. Any degradation halts the advance and, if needed, rolls the allocation back to 0%.

Canary release is a specific, narrower case of progressive rollout: instead of segmenting by percentage of users, you release first to a subset of servers or instances (the term comes from canaries used in mines to detect gas before it reached the miners), observe the health of the infrastructure in that subset, and only then expand to the rest of the fleet. It’s as much an infrastructure deploy technique as a flagging one, and the two combine well: a canary release on the infrastructure, with a release flag controlling who, within that canary, actually sees the new feature.

The most commonly cited progressive rollout pattern follows stages similar to these, adjusted to traffic volume and the team’s risk appetite:

Stage Typical audience What you watch
Internal Team and QA (dogfooding) Obvious bugs, before any real user sees it
1% Minimal slice of production Error rate, latency, exceptions in the logs
5-10% Larger but still small sample Business metrics start to carry meaning
25-50% Half or more of the audience Confirms behavior holds up at scale
100% Entire audience Full rollout; the flag can start being considered for removal

Every stage advance should be conditioned on guardrail metrics: error rate, latency, and business indicators that can’t get worse. If any of them degrade, the answer is to pull the allocation back, not push forward hoping it “stabilizes on its own.”

The kill switch: rollback without a new deploy

The mirror image of a progressive rollout is the emergency stop. Because the flag lives outside the deploy pipeline, turning a feature off during an incident is a configuration change, not a code change, which is what makes it fast enough to matter during an outage.

Rollback timeline: flag kill switch vs a new deploy Reverting a bad feature with a flag kill switch takes seconds, a single configuration change. Reverting the same problem by shipping a new deploy takes much longer, because it requires a code change, a build, a test run, and a full deploy. Flag kill switch Toggle off (seconds) New deploy to revert code fix review build+test deploy ~seconds to minutes ~30 minutes to hours, under pressure
The gap widens further when the deploy pipeline is slow, requires a second approver, or the incident happens outside business hours. A kill switch removes the pipeline from the critical path entirely.

Market tools (a neutral view)

There is no single “best” feature flag tool, only the right one for your context: team size, budget, whether you already pay for analytics or experimentation with one of these vendors, and how much infrastructure control you want to keep in-house. A neutral snapshot of what each offers, based on each vendor’s own public documentation:

Tool Model Stated focus
LaunchDarkly Commercial SaaS Mature feature management platform, with advanced targeting, integrated experimentation, and a strong emphasis on governance and audit for large teams
Unleash Open source (core) + optional SaaS Can be self-hosted, with the core released under an open-source license; states a focus on data sovereignty and avoiding vendor lock-in
Flagsmith Open source + SaaS Also offers a self-hosted option; positions itself as an alternative with solid SDKs and a simple REST API, plus a generous free plan for small teams
PostHog SaaS (with self-hosting) Feature flags as part of a broader product suite (analytics, session replay, experiments), useful for teams already using PostHog for other things
Statsig Commercial SaaS Strong integration between feature flags and statistical experimentation, with an emphasis on metrics and native A/B testing on top of the same flagging infrastructure

Criteria that tend to matter more in practice than the brand name:

This comparison is a snapshot of what each vendor states publicly; pricing, free-tier limits, and specific capabilities change often, so it’s worth confirming against the current documentation of each one before deciding.

Risks and best practices

A feature flag reduces deploy risk, but it introduces a different one if it isn’t managed: complexity that accumulates quietly until it becomes technical debt that’s hard to unwind. The most commonly cited risks in the literature, and the practice that addresses each one:

Zombie flags (technical debt)

This is the most widely discussed risk of all: a flag that has already done its job (the feature has been fully rolled out and stable for months) but that nobody removed from the code. It stays there, with the full if and else branches, requiring anyone reading that section to understand both possible paths, even though one of them never runs anymore. Multiplied across dozens or hundreds of flags accumulated over years, the result is code where no one is confident which flag combinations are even still possible, and the testing surface explodes. Documentation from LaunchDarkly, ConfigCat, and Statsig all converge on the same diagnosis: unmanaged flags are the single biggest source of flag-related technical debt.

Best practices to avoid it:

Combinatorial explosion of states

Every active flag doubles, in theory, the number of possible system behavior combinations. With a handful of flags this is irrelevant; with dozens running at once, testing every combination by hand becomes impossible, and unexpected interactions between two flags (one turns on a new flow, another changes a dependency of that flow) become a real source of production bugs that only show up for a specific slice of users.

Mitigation: keep the number of simultaneously active flags as low as possible (which reinforces the removal point above), document known dependencies between flags, and use a testing matrix (a table of relevant combinations, not every mathematically possible one) for the scenarios that actually matter to the business.

Testing matrix of relevant flag combinations Instead of testing every mathematically possible combination between active flags, a testing matrix lists only the combinations that actually matter to the business, marking which ones have already been verified. Scenario Flag A Flag B Verified new user on off yes legacy account on on pending enterprise plan off on yes
The matrix prioritizes plausible, business-relevant combinations (new user, legacy account, specific plan), not the full list of 2 raised to the number of flags, which grows too fast to be useful.

Consistency of the user experience

A user who switches tabs, switches devices, or reloads the page can’t see a feature flicker in and out inconsistently. That requires a stable targeting unit (usually a deterministic hash of the user ID or a persistent anonymous identifier), the same concern that already exists in A/B testing to guarantee every visitor consistently sees the same variation.

Governance and audit

In larger teams, “who changed this flag, when, and why” needs an answer. Dedicated feature management tools solve this natively with an audit log; homegrown solutions (a database table, an environment variable) usually don’t have this for free, and it’s worth adding before its absence turns into an unexplained incident.

Performance and single points of failure

Evaluating a flag can’t become a bottleneck or a single point of failure: if the service that resolves flags goes down, the system needs to degrade to a safe default behavior (usually, the flag off), never hang the entire application waiting for a response that never arrives. It’s the same “fail silently to the safe state” principle any third-party snippet embedded on a page should follow.

How feature flags relate to Donnu’s experimentation engine

Everything this guide covered about release, ops, and permission flags happens before any statistics enter the picture: they are on/off/targeting decisions, with no hypothesis, no calculated sample, no p-value. The point where a plain flag turns into real experimentation is when you stop asking “is this on for the people I want” and start asking “does this variation convert better than the other, with enough confidence for me to decide based on it.”

That’s exactly where an A/B testing engine comes in: Donnu uses the same stable targeting mechanism as a feature flag (each visitor lands on a variation and stays there) to power a test with honest statistical design behind it, from sample size calculation all the way to an honest Bayesian read of the result. If you already use feature flags to control releases and want to turn one of them into a rigorous experiment, our guide on feature flags vs A/B testing walks through exactly that transition, and how to run an A/B test covers the step-by-step once you’re ready to measure instead of just toggle.

Automate this on Donnu

You just saw the gap between flipping a feature off for safety and comparing two variations with statistical rigor: the first is flag management, the second is experimentation. Most teams build a homegrown flag (an environment variable, a database column) to gate a rollout, then hit a wall the moment someone asks “but did it actually convert better?”, because a plain on/off switch has no sample size, no significance test, and no way to tell a real lift from noise.

Donnu A/B focuses on that second part: when one of your release or experiment flags needs to become a data-backed decision, with a calculated sample size, an honest Bayesian read, and none of the flicker that ruins the user experience, you don’t need to build that statistical engine from scratch. Start a 14-day free trial and see what it looks like to take a feature from “it’s turned on” to “we know it performs better.” For more depth first, see the full breakdown of feature flags vs A/B testing, the comparison of running the decision client-side or server-side, and statistical significance in A/B testing for the math behind calling a winner.

References

Frequently asked questions

What is a feature flag, in one sentence?
A feature flag is a switch in your code that decides, at runtime and without a new deploy, whether a piece of functionality is visible or active for a given user, a group of users, or everyone, which lets you separate the moment code reaches production from the moment it actually reaches users.
Is a feature flag the same thing as an A/B test?
No. A flag is the control mechanism (turn on, turn off, target a segment); an A/B test is a statistical method that uses that mechanism to compare variations with calculated sample size and significance. Every experiment relies on flags under the hood, but most flags (release, ops, and permission flags) never become an experiment. See the full breakdown in our dedicated guide on feature flags vs A/B testing.
Does a feature flag replace version control (Git)?
No, they solve different problems and work together. Git manages the history and integration of source code; a flag controls behavior in production after that code has already been merged and deployed. That separation is what makes trunk-based development possible: merging to main every day without exposing unfinished work, a practice Martin Fowler and Pete Hodgson describe as one of the core uses of feature toggles.
What is the biggest risk of using feature flags?
Flag technical debt, often called a zombie flag: a toggle that already did its job (the feature is fully rolled out and stable) but was never removed from the code. Every live flag multiplies the execution paths you have to reason about and raises the odds that two flags interact in a way nobody predicted. The fix is process, not tooling: an owner per flag, an expiration target, and a recurring cleanup routine.
Should a feature flag be evaluated client-side or server-side?
It depends on where the decision needs to happen and what is at stake. Client-side (in the browser or app) is simpler to install and common for marketing and onboarding changes, but it ships the flag logic inside the bundle sent to the user. Server-side is more robust for sensitive business rules, permissions, and private data, because the decision never leaves your backend. The full trade-off comparison lives in our client-side vs server-side guide.
Do I need a paid tool to start using feature flags?
Not necessarily. You can start with a simple flag read from an environment variable or a database table. Dedicated platforms like LaunchDarkly, Unleash, Flagsmith, PostHog, or Statsig become worth it once you need attribute-based targeting, percentage rollouts, a dashboard non-engineers can use, and an audit trail, without building that infrastructure by hand.