You just deployed a new feature and it's breaking everything. Users are complaining. Your boss is asking questions. You're frantically trying to roll back.
Feature flags would have prevented this. Here's how they work and how to implement them — even if you've never used them before.
What Are Feature Flags?
A feature flag is an if statement that wraps your new code:
if feature_enabled('new-checkout-flow', user_id='user_123'):
return new_checkout()
else:
return old_checkout()
The flag is controlled by a configuration, not by your code. You can turn features on/off without deploying. You can roll them out to 10% of users first. You can target specific users for beta testing.
The Simplest Implementation
You don't need a paid service to start. A JSON file works:
{
"new-checkout-flow": false,
"dark-mode": true,
"ai-search": false
}
import json
def feature_enabled(flag_name: str) -> bool:
with open('flags.json') as f:
flags = json.load(f)
return flags.get(flag_name, False)
This is fine for a solo project. But it falls apart when you need:
- Percentage rollouts — 10% of users first, then 25%, then 100%
- User targeting — beta testers see the feature, everyone else doesn't
- Instant toggles — turn off a broken feature in seconds, not deploy-minutes
Level Up: Percentage Rollouts
The key insight: hash the user ID to get a consistent number between 0-99. If the number is below your rollout percentage, the user sees the feature.
import hashlib
def is_in_rollout(flag_name: str, user_id: str, percentage: int) -> bool:
# Hash user_id + flag_name for consistent bucketing
key = f"{flag_name}:{user_id}"
hash_value = int(hashlib.md5(key.encode()).hexdigest(), 16)
bucket = hash_value % 100
return bucket < percentage
# 10% rollout
is_in_rollout('new-checkout', 'user_123', 10) # Always returns same result for same user
is_in_rollout('new-checkout', 'user_456', 10) # Different user, different result
The MD5 hash ensures the same user always gets the same result (no flickering between old and new), and users are distributed evenly.
You can try this interactively:
# Free API — simulate a rollout across 1000 users
curl -s 'https://flagbit.anethoth.com/api/v1/rollout/simulate?flag=new-checkout&percentage=25&user_count=100' | jq '.summary'
Response:
{
"total_users": 100,
"included": 25,
"excluded": 75,
"actual_percentage": 25.0
}
Level Up: Targeting Rules
Sometimes you want a feature enabled for:
- All users with
plan: pro(beta features for paying customers) - Users in
country: USonly (compliance-gated features) - Your internal team emails (dogfooding)
def evaluate_flag(flag_config: dict, user_context: dict) -> bool:
rules = flag_config.get('rules', [])
for rule in rules:
attribute = rule['attribute'] # e.g., 'plan'
operator = rule['operator'] # e.g., 'equals'
value = rule['value'] # e.g., 'pro'
user_value = user_context.get(attribute)
if operator == 'equals' and user_value == value:
return True
elif operator == 'contains' and value in str(user_value):
return True
elif operator == 'in' and user_value in value:
return True
# Check percentage rollout as fallback
percentage = flag_config.get('percentage', 0)
if percentage > 0:
return is_in_rollout(flag_config['name'], user_context.get('id', ''), percentage)
return flag_config.get('enabled', False)
You can test targeting rules without writing code:
# Free playground — no signup required
curl -s -X POST 'https://flagbit.anethoth.com/api/v1/evaluate-playground' \
-H 'Content-Type: application/json' \
-d '{
"flag": {"name": "new-checkout", "enabled": true, "rules": [{"attribute": "plan", "operator": "eq", "value": "pro"}]},
"context": {"plan": "pro", "country": "US"}
}'
When to Use Feature Flags
Yes:
- Risky features (payment processing changes, auth changes)
- Gradual rollouts (new UI, new algorithms)
- A/B tests (try two approaches, measure which converts better)
- Kill switches (turn off a feature that's causing errors)
- Premium features (flag check = plan check)
No:
- Trivial changes (copy updates, CSS tweaks)
- Features you're 100% shipping to everyone
- Temporary debugging code
The Progressive Rollout Strategy
Here's the rollout pattern used by companies like GitHub, Stripe, and Netflix:
- 0% — Feature merged behind a flag. Only visible to developers.
-
Internal — Enable for your team via targeting rule (
email contains @yourcompany.com) - 1% — Canary release. Watch error rates and metrics.
- 10% — Wider canary. Enough traffic to spot edge cases.
- 50% — Half your users. Compare metrics between control and treatment.
- 100% — Full rollout. Remove the flag from code in the next sprint.
The key: increase slowly, monitor at each step, and have a one-click killswitch.
Choosing a Feature Flag Tool
| Tool | Price | Best For |
|---|---|---|
| JSON file | Free | Solo projects |
| FlagBit | Free–$49/mo | Small teams, API-first |
| LaunchDarkly | $10/seat/mo | Enterprise |
| Unleash | Free (self-host) | Control freaks |
| Statsig | Free tier | A/B test focused |
Quick Start
Want to try feature flags right now? Here's a 30-second setup:
# 1. Sign up (free, no credit card)
curl -s -X POST https://flagbit.anethoth.com/api/v1/signup \
-H 'Content-Type: application/json' \
-d '{"email": "dev@example.com"}'
# 2. Create a project
curl -s -X POST https://flagbit.anethoth.com/api/v1/projects \
-H 'X-API-Key: YOUR_KEY' \
-H 'Content-Type: application/json' \
-d '{"name": "my-app"}'
# 3. Create a flag
curl -s -X POST https://flagbit.anethoth.com/api/v1/projects/PROJECT_ID/flags \
-H 'X-API-Key: YOUR_KEY' \
-H 'Content-Type: application/json' \
-d '{"name": "new-checkout", "enabled": false}'
# 4. Evaluate in your app
curl -s 'https://flagbit.anethoth.com/api/v1/evaluate?sdk_key=SDK_KEY&flag=new-checkout&user_id=user_123'
That's it. You now have a feature flag system. Turn features on/off from the API, roll out to percentages of users, and target specific user segments.
Resources:
- FlagBit — Feature flags API for small teams (free tier)
- A/B Test Sample Size Calculator — Calculate how long to run experiments
- Rollout Simulator — Visualize percentage rollouts
- Framework Guides — Feature flags in React, Python, Go, and 14 more frameworks
Top comments (0)