← All posts

What are feature flags? A practical guide with examples

November 6, 2026

A feature flag is a switch in your code that turns a feature on or off without a new deployment. You ship the code turned off, then decide separately when each user gets it.

At its simplest, a flag is an if statement:

if (flags.isEnabled("new-checkout", user.id)) {
  return renderNewCheckout();
}

return renderCurrentCheckout();

Instead of being fixed in your code, the value of new-checkout comes from a service or a config you can change while your app is running. Change the value, and the behavior changes.

Why teams use feature flags

Feature flags separate two things that usually happen at once: deploying code and releasing a feature. That gives you a few practical advantages.

  • Safer releases: Turn a feature on for your own team or one customer first, and widen the release once it's working.
  • Faster incident response: If a new feature causes problems, turn it off. You don't need to wait for a rollback or a new build.
  • Smaller merges: Unfinished work can go to your main branch behind a disabled flag, so long-lived branches and painful merges become less common.
  • Release timing that suits the business: Engineering can deploy when the code is ready, and the feature can go live with the launch announcement.

The main types of feature flags

Flags do different jobs, and they shouldn't all live for the same amount of time.

Type What it does How long it lasts
Release flag Hides a feature until it's ready Days or weeks
Kill switch Turns off a risky feature or dependency during an incident As long as the risk exists
Experiment flag Compares versions of a feature, such as in an A/B test The length of the experiment
Permission flag Gives certain customers or plans access to a feature Often permanent

Knowing which type you're adding tells you when to remove it, or whether it should stay.

How feature flags work

Most feature flag systems have three parts:

  1. A place to manage flags, usually a dashboard or API, where you change a flag's state.
  2. A store for the current values, which is the source of truth.
  3. An SDK or API call in your app, which asks whether a flag is on for a given user.

The biggest design difference is where the check happens.

  • Remote evaluation: Your app calls a service for each check. The answer is always current, but each check adds a network call.
  • Local evaluation: The SDK keeps flag values in memory and receives updates in the background. Checks are nearly instant, and your app can keep using its last known values if the service is unreachable. Serverless platforms need more care, because instances can pause between requests and miss updates.

Rolling out a feature step by step

A typical release looks like this:

  1. Deploy with the flag off. The code reaches production, but nobody sees the change.
  2. Turn it on for your team. Test it with real production data and services.
  3. Turn it on for a few customers. Watch your errors, performance, and support messages.
  4. Turn it on for everyone. Keep the flag available until you're confident.
  5. Remove the flag. Delete the check and the old code path.

If something goes wrong at any step, turn the flag off and fix the problem without an emergency deployment.

Feature flags or config files?

Config files and environment variables suit values that rarely change and can wait for a restart or a deployment, such as a database URL. Feature flags suit decisions you may need to change while your app is running, or that differ between users.

Secrets don't belong in either one. Keep them in a dedicated secrets manager.

Common mistakes to avoid

  • Keeping flags forever: Old release flags pile up and make code harder to follow. Give each one an owner, and add a ticket to remove it when you create it.
  • Vague names: new-checkout tells people what it controls. flag-2 doesn't. Choose carefully, because some systems don't let you rename a flag's key.
  • Testing only one path: While a flag exists, both versions can run in production, so test both.
  • No sensible default: Decide what happens if a flag can't be loaded. Usually, that means falling back to the existing behavior.
  • No record of changes: A flag change can affect production as much as a deployment. During an incident, you need to know who changed what, and when.

When you don't need a feature flag

A flag adds a code path you have to maintain, so skip it for small, low-risk changes that are easy to revert. Flags also can't undo everything: if a release includes a database migration, turning off the flag won't reverse the migration. Make those changes backward compatible, so both code paths keep working.

Try it yourself

The fastest way to understand feature flags is to add one to a real app. Our Next.js tutorial walks through a flag, a release to a single user, and a kill switch.

We built flagr.dev for on/off flags and per-customer rollouts, with SDKs for TypeScript, Python, Go, Kotlin/JVM, and PHP. It's a good fit for controlling who gets a feature and when. It doesn't do percentage rollouts or A/B tests, so experiment flags need a different tool.