Feature Flags in Production: Implementation Patterns Beyond Boolean Toggles
Feature flags started as simple boolean toggles: feature enabled or disabled. But in production, they evolve into a full release management system. Percentage rollouts, user targeting, A/B testing, kill switches, and operational flags — each pattern serves a different purpose and requires different implementation.
Here is how we implement feature flags at AIDToolStack and the patterns that scale beyond simple toggles.
Why Feature Flags
Without feature flags: code ships to everyone simultaneously. If the feature breaks, you deploy a rollback (minutes to hours of impact). The blast radius is 100% of users.
With feature flags: code ships to production but is disabled. You enable for 1% of users, monitor, expand to 10%, monitor, and eventually reach 100%. If the feature breaks at 1%: disable the flag. Instant recovery, 1% blast radius.
Additional benefits: decouple deployment from release (merge to main without releasing to users), enable trunk-based development (no long-lived feature branches), A/B test features (show different experiences to different users), and emergency kill switches (disable a feature instantly without deploying).
Pattern 1: Simple Boolean Toggle
The most basic flag: a feature is either on or off for everyone.
Use for: kill switches (disable a feature during an incident), maintenance mode (temporarily hide a feature under development), and operational flags (enable verbose logging in production during debugging).
Implementation: check the flag value in your code. If true: render the feature. If false: render the previous behavior or nothing.
Do NOT overuse this pattern. If a flag is never targeted at specific users or rolled out gradually: it might not need to be a feature flag at all. A simple environment variable or config setting might suffice.
Pattern 2: Percentage Rollout
The flag is enabled for a percentage of users. Start at 1%, increase to 5%, 25%, 50%, 100% over days or weeks.
Use for: new features with uncertain performance impact (does the new search algorithm handle production load?), user-facing changes with uncertain reception (do users prefer the new UI?), and infrastructure changes with risk (new database connection pooling — works at scale?).
Implementation: hash the user ID to determine their percentage bucket. A user in bucket 1-5 gets the feature at 5% rollout. The hash ensures consistency: the same user always gets the same experience (no flickering between enabled/disabled on each request).
Key detail: the hash must be deterministic. User ABC always maps to bucket 37. Whether the feature is enabled at 37% or 50% determines their experience. This prevents the same user seeing the feature on one page load and not the next.
Pattern 3: User Targeting
Enable the flag for specific users or user segments. Internal team members see the feature first. Then beta users. Then everyone.
Use for: internal testing (team uses the feature in production before any external user sees it), beta programs (opted-in users get early access), and enterprise features (features available only to paying users on specific plans).
Implementation: check if the current user matches targeting rules. Rules can be: specific user IDs (internal team), user attributes (plan: "pro", role: "admin"), or custom segments (users who opted into beta in their settings).
Pattern 4: A/B Testing
Multiple feature variants shown to different user segments. Measure which variant performs better.
Use for: UI experiments (button color, layout changes, copy variations), algorithmic changes (new recommendation algorithm vs current), and pricing experiments (different pricing tiers shown to different cohorts).
Implementation: assign users to variants (A, B, or control). Track conversion metrics per variant. Run for a statistically significant duration. Choose the winner.
Important: A/B testing feature flags require analytics integration. Without measurement: you are just randomly showing different things to different users with no learning.
Implementation Architecture
Our feature flag system (simplified): flags stored in a database table (name, type, rules, enabled status), flag evaluation on the server (check user context against flag rules), client-side flag values passed via server response (no client-side flag fetching — avoids flicker), and admin UI for creating and modifying flags.
Server-side evaluation is critical: do not fetch flag values from the client. This causes: a flash of wrong content (feature appears then disappears, or vice versa), an additional network request on every page load, and security issues (users can modify client-side flag values).
Instead: evaluate flags server-side and pass the results to the client as part of the initial page render. No flicker, no extra request, no manipulation.
Flag Lifecycle Management
Feature flags are technical debt if not managed. A flag created in January that is still in the code in December (fully enabled for 11 months) is dead code around a conditional.
The lifecycle: create flag (clearly named, documented purpose), develop behind flag (code references the flag, feature disabled by default), rollout (gradually enable, monitor), full release (flag enabled for 100%), and cleanup (remove flag and conditional logic from code — the feature is now permanent).
The cleanup step is where teams fail. Schedule cleanup: when a flag reaches 100% for 2+ weeks without issues, create a ticket to remove the flag code. Remove the conditional, remove the old code path, and delete the flag from the database.
We track flag age: any flag older than 90 days at 100% rollout gets automatically flagged for cleanup in our task backlog.
Flag Naming Conventions
Bad names: flag_1, new_feature, test_something. These are meaningless in 3 months.
Good names: enable_ai_search_results, show_pro_pricing_v2, use_new_recommendation_algorithm. The name should describe: what the flag does, at a glance, without reading code.
Convention: verb_noun_context. enable_dark_mode, show_onboarding_flow, use_redis_cache.
Common Mistakes
Mistake 1: flags in nested conditionals. If feature A is behind a flag and feature B (which depends on A) is behind another flag: you get combinatorial complexity. A enabled + B enabled, A enabled + B disabled, A disabled + B enabled, A disabled + B disabled. Each combination might behave differently.
Solution: dependent features should share a flag, or the dependent feature's flag should require the parent flag to be enabled.
Mistake 2: testing only the enabled path. If a flag is disabled in production: does the disabled path still work correctly? Test both paths. When you eventually remove the flag: you are removing the disabled path, which must work until removal.
Mistake 3: using flags for permanent configuration. If something will ALWAYS be a toggle (admin feature enable/disable): use application configuration, not a feature flag. Feature flags are temporary. Configuration is permanent.
Build vs Buy
Build your own: appropriate for simple use cases (10-20 flags, boolean toggles, basic percentage rollouts). A database table, an evaluation function, and an admin page. Maybe 2-3 days of work.
Buy (LaunchDarkly, Statsig, Flagsmith, PostHog): appropriate for complex use cases (hundreds of flags, multi-variate testing, detailed analytics, audit trail, scheduling). These services provide: SDKs for every platform, real-time flag propagation, analytics and experimentation, audit logging, and segments and targeting rules.
Our choice: we built a simple system for our scale (under 30 active flags). If we needed complex experimentation or had a larger team: we would use a service.
The Cultural Shift
Feature flags change how you work. Instead of: develop on a branch for weeks, merge a massive PR, hope it works in production — you: merge small PRs daily (behind a flag), test in production with real data, roll out gradually with confidence, and roll back instantly if needed.
This requires trust: management trusts that code in production behind a flag is safe. Engineers trust that flags will be cleaned up (not accumulated indefinitely). QA trusts that both flag paths are tested.
The payoff: faster deployment, lower risk releases, and the ability to ship incomplete features without blocking other work. Feature flags are not just a technical tool — they are a deployment philosophy.
Written by AIDToolStack Editorial
The AIDToolStack editorial team reviews developer tools, AI products, and MCP servers with hands-on testing and honest assessments. We use the tools we review every day in production.
References & Further Reading
Related Posts
Sponsor Our Newsletter
Reach thousands of developers who are actively evaluating AI tools, MCP servers, and dev infrastructure. Our weekly newsletter goes to engaged technical decision-makers.
All sponsored content is clearly labeled per our editorial policy.