Back to blog

What Are Feature Flags? A Practical Guide for Developers

·12 min read

Feature flags (also called feature toggles) let you turn features on or off in your application without deploying new code. Instead of shipping a feature to everyone at once, you wrap it in a conditional check. The feature exists in your codebase, but it's only visible when the flag is enabled.

if feature_flags.enabled("new_checkout"):
show_new_checkout()
else:
show_old_checkout()

That's the core idea. The rest of this post covers why this simple concept changes how you ship software, with practical examples you can apply today.

Why Feature Flags Matter

Ship Without Fear

The traditional deployment model looks like this: you write code, merge it, deploy it, and hope nothing breaks. If it does, you either roll back the entire deployment or push a hotfix.

With feature flags, you deploy the code with the feature turned off. Then you enable it gradually, maybe for 5% of users first, then 20%, then everyone. If something goes wrong, you flip the flag off. No rollback. No hotfix. No downtime.

This changes your relationship with deployments. They become boring, which is exactly what you want.

Test in Production

Staging environments never perfectly mirror production. Different data, different load, different edge cases. Feature flags let you test new features with real users and real data while limiting the blast radius.

A common pattern: enable the feature only for your team first.

if feature_flags.enabled("new_search", user={"email": "you@company.com"}):
return new_search_results(query)
else:
return old_search_results(query)

Your team uses the new feature in production for a week. If it works, you roll it out to everyone. If it doesn't, nobody outside your team ever saw it.

Gradual Rollouts

Percentage-based rollouts are one of the most powerful feature flag capabilities. Instead of a binary on/off, you can release a feature to a percentage of your users.

# Enable for 10% of users
if feature_flags.enabled("new_pricing_page", user={"user_id": "42"}):
show_new_pricing()

The flag system uses consistent hashing, so the same user always gets the same result. User "42" either always sees the new pricing page or never does, regardless of how many times they visit. This consistency is important for user experience.

You start at 10%, monitor your metrics, bump to 25%, then 50%, then 100%. If your error rate spikes at 25%, you drop back to 10% and investigate.

Decouple Deployment from Release

This is the most underrated benefit. Without feature flags, deploying code and releasing a feature are the same event. With flags, they're separate.

Your team can merge code to main continuously, deploy it, and the feature stays hidden behind a flag until you're ready to release. This eliminates long-lived feature branches, painful merges, and the anxiety of "big bang" releases.

A developer can ship half-finished work behind a flag. It's deployed, reviewed, and tested, but invisible to users until the flag is turned on.

Real-World Use Cases

Kill Switches

Your new recommendation engine is causing high CPU usage. Without a feature flag, you'd need to deploy a fix. With a flag, you toggle it off from a dashboard. The system falls back to the old behavior instantly.

Every critical feature should have a kill switch. Database migration going wrong? Kill switch. Third-party API failing? Kill switch. New ML model returning bad results? Kill switch.

A/B Testing

Feature flags naturally enable A/B testing. Show version A to half your users and version B to the other half, then measure which performs better.

variant = feature_flags.get_value("checkout_version", user={"user_id": user.id}, default="A")
if variant == "B":
show_streamlined_checkout()
else:
show_original_checkout()

Per-Customer Features

If you're building a SaaS, feature flags let you enable features for specific customers without building a complex permissions system.

if feature_flags.enabled("advanced_analytics", user={"org_id": "acme_corp"}):
show_advanced_analytics()

Enterprise customer wants early access to a feature? Enable their flag. Beta tester wants to try something new? Enable their flag. No code changes, no deployments.

Maintenance Mode

Need to take a service down for maintenance? A feature flag can show a maintenance page to users while your team continues to access the full application.

How Feature Flags Work Under the Hood

A feature flag system has three parts:

  1. A place to store flag configurations. This could be a database, a config file, or a third-party service. The configuration says: which flags exist, are they enabled, what are the rollout rules.
  2. An SDK in your application. A small library that your code calls to check flag values. The SDK fetches configurations, caches them locally, and evaluates rules without making a network call for every check.
  3. A way to manage flags. A dashboard or API where you create flags, toggle them, set rollout percentages, and add targeting rules.

The typical flow:

  1. Admin enables a flag in the dashboard
  2. The configuration is updated (in a database, CDN, or config file)
  3. SDKs poll for the latest configuration
  4. Your application code checks the flag and gets the current value
  5. The evaluation happens locally in the SDK: sub-millisecond, no network call

The key insight is that flag evaluation must be fast and reliable. If checking a flag adds latency to every request, or if the flag service going down breaks your application, you've made things worse, not better. Good SDKs cache configurations locally and evaluate rules in-memory.

Best Practices

Name Your Flags Well

Flag names should be descriptive and consistent. Use a naming convention like feature_name or area_feature_action.

Good: new_checkout_flow, search_v2, dark_mode

Bad: flag1, test, johns_feature

You'll have dozens of flags eventually. Clear names prevent confusion.

Clean Up Old Flags

Feature flags are meant to be temporary. Once a feature is fully rolled out and stable, remove the flag from your code and your flag service. Stale flags accumulate like dead code. They confuse new developers and make the codebase harder to understand.

A good rule: if a flag has been at 100% for more than two weeks, it's time to remove it.

Keep an Audit Log

You need to know who changed what and when. When a flag gets toggled at 2 AM and causes a spike in errors, the audit log tells you exactly what happened.

Every flag change should be recorded: who changed it, what the old value was, what the new value is, and when.

Set Safe Defaults

If your flag service is unreachable, your application should still work. The default value for every flag should be the safe, conservative option, usually the existing behavior.

# If the flag doesn't exist or can't be evaluated, default to False (old behavior)
if feature_flags.enabled("new_checkout", default=False):
show_new_checkout()
else:
show_old_checkout()

Don't Nest Flags

Avoid checking one flag inside another flag. This creates combinatorial complexity that's nearly impossible to reason about.

# Don't do this
if feature_flags.enabled("new_ui"):
if feature_flags.enabled("new_search"):
if feature_flags.enabled("new_results"):
...

Each flag should control one independent behavior.

Getting Started

The simplest way to start is with a single boolean flag for a feature you're about to ship. You don't need a complex setup, just a flag, a toggle, and an SDK.

If you want to try it with zero setup, Switchbox is a feature flag service that serves configurations from a CDN with a zero-dependency Python SDK:

pip install switchbox-flags
from switchbox import Switchbox
client = Switchbox(sdk_key="your-sdk-key-from-dashboard")
if client.enabled("new_feature", user={"user_id": "42"}):
show_new_feature()

The SDK fetches a static JSON file from a CDN, evaluates rules locally in under a millisecond, and polls for updates every 30 seconds. No server in the read path.

Whether you use Switchbox, another service, or build your own, the important thing is to start using feature flags. Once you do, you'll wonder how you ever shipped without them.