We shipped a checkout redesign to 100% of users on a Friday afternoon. Conversion dropped 12% over the weekend. By Monday morning, we'd lost ₹3.2 lakh in revenue. If we'd had a feature flag, we could have rolled back in 10 seconds instead of waiting for a hotfix deployment. That's the day we adopted feature flags for every significant change.
What We'll Cover
Types of Feature Flags
Not all flags are the same. Using the wrong type for your use case leads to flag sprawl and technical debt.
| Type | Purpose | Lifetime | Example |
|---|---|---|---|
| Release flag | Control when a feature becomes visible | Days to weeks | "New checkout flow" — roll out to 10%, then 50%, then 100% |
| Experiment flag | A/B testing, measuring impact | Weeks to months | "Green vs blue CTA button" — 50/50 split, measure conversion |
| Ops flag (kill switch) | Disable features during incidents | Permanent | "Disable recommendations" — turn off when recommendation service is down |
| Permission flag | Gate features for specific users/plans | Permanent | "Advanced analytics" — only for Enterprise plan customers |
Release flags should be temporary — once the feature is fully rolled out, remove the flag. Ops and permission flags are permanent parts of your system. This distinction matters for lifecycle management.
Implementation Patterns
Basic Implementation
// Simple feature flag service
interface FeatureFlags {
isEnabled(flagName: string, context?: UserContext): boolean;
}
// Usage in application code
function renderCheckout(user: User) {
if (featureFlags.isEnabled('new-checkout-flow', { userId: user.id })) {
return renderNewCheckout(user);
}
return renderOldCheckout(user);
}
// Usage in API route
app.post('/api/orders', async (req, res) => {
if (featureFlags.isEnabled('batch-order-processing')) {
return batchOrderHandler(req, res);
}
return singleOrderHandler(req, res);
});
Flag Evaluation Rules
Flags evaluate to true or false based on rules. Common targeting rules:
- Percentage rollout: 10% of all users see the new feature (consistent per user via hash)
- User targeting: Specific users or groups (internal team, beta testers, enterprise customers)
- Attribute targeting: Users in India, users on mobile, users who signed up after a certain date
- Environment: Enabled in staging, disabled in production
Consistent Hashing for Percentage Rollouts
When you set a flag to 10%, the same user should always see the same variant. Don't use Math.random() — use a hash of the user ID:
function isInPercentage(userId: string, flagName: string, percentage: number): boolean {
// Hash user ID + flag name for consistent assignment
const hash = murmurhash3(`${flagName}:${userId}`);
const bucket = hash % 100;
return bucket < percentage;
}
// User "usr_abc" gets bucket 37 for "new-checkout"
// At 10%: excluded (37 >= 10)
// At 50%: included (37 < 50)
// At 100%: included
// The user's assignment only changes when you change the percentage
Gradual Rollout Strategies
The Safe Rollout Plan
- 0% → Internal team (dogfooding) — Enable for employees only. Use for 2-3 days. Catch obvious issues
- 1% → Canary — Real users, minimal blast radius. Monitor error rates, latency, conversion. Run for 24 hours
- 10% → Early rollout — Statistically significant sample. Compare metrics between flag-on and flag-off cohorts. Run for 2-3 days
- 50% → Broad rollout — If metrics are good at 10%, expand. This is also where you can run A/B tests for conversion impact
- 100% → Full rollout — All users. Monitor for 1 week
- Remove flag — After 1 week at 100% with no issues, delete the flag and the old code path
Tools Comparison
| Tool | Best For | Pricing | Our Take |
|---|---|---|---|
| LaunchDarkly | Enterprise, complex targeting, experimentation | From $10/seat/month | Category leader. Best UI and SDK support. Worth the cost for 20+ flags |
| Unleash | Self-hosted, open source | Free (OSS) or hosted from $80/month | Best open-source option. Self-host for data sovereignty. UI is decent |
| ConfigCat | Simple flags, small teams | Free (10 flags) → $39/month | Simplest to set up. Good for startups. Limited targeting |
| Flagsmith | Feature flags + remote config | Free (OSS) or hosted from $45/month | Good alternative to Unleash with better UI. Combines flags with config management |
| DIY (database/config) | 1-5 simple on/off flags | Free | Fine for simple toggles. Don't build a flagging system from scratch — buy or use OSS |
Flag Lifecycle Management
Technical debt from abandoned flags is the #1 complaint we hear. A codebase with 200 stale flags is harder to maintain than one without flags.
Rules We Follow
- Every release flag gets an expiry date. Set it when creating the flag. 30 days after full rollout, the flag must be removed
- Flag cleanup is part of the definition of done. A feature isn't "done" until the flag is removed and the old code path is deleted
- Monthly flag audit. Review all flags older than 30 days. Is it fully rolled out? Remove it. Is it at 50% for 3 months? Make a decision and move on
- Name flags with intent.
release-new-checkout-q4-2025is better thanflag-123. When someone sees it in 6 months, they should know what it's for
Common Pitfalls
| Pitfall | What Happens | Prevention |
|---|---|---|
| Flag combinatorics | Flag A × Flag B × Flag C = 8 possible states. Testing all combinations is exponential | Keep flags independent. If two flags interact, make one depend on the other explicitly |
| Stale flags | 200 flags, nobody knows which are active. New devs afraid to remove any | Expiry dates, monthly audits, ownership per flag |
| Testing gaps | Tests only run with flags on. The flag-off path silently breaks | CI runs tests with all flag combinations for critical paths. Or at minimum, both on and off |
| Performance | Flag evaluation on every request adds latency if flags are fetched remotely | Cache flag values locally with TTL. Most flag SDKs do this automatically |
Frequently Asked Questions
When should we use feature flags vs feature branches?
Feature flags for changes that affect existing functionality or need gradual rollout. Feature branches for isolated new code. The best teams use both: develop on a short-lived branch, merge to main behind a feature flag, then roll out gradually. This gives you both code isolation and deployment control.
How many feature flags is too many?
There's no magic number, but if you have more than 50 active release flags, something is wrong — flags aren't being cleaned up. Permanent flags (ops, permissions) don't count toward this limit. We target under 20 active release flags at any time for a typical team of 10-15 developers.
Can feature flags replace staging environments?
Not entirely, but they reduce staging's importance. With flags, you can test in production with real data (for internal users first). Staging is still useful for integration testing and catching obvious issues before any real user exposure. Think of flags as complementing staging, not replacing it.