The traditional model of software deployment ties code deployment directly to feature release. When code reaches production, users immediately see the changes. This coupling creates pressure to delay deployments until features are fully polished and thoroughly tested, which in turn leads to large, risky releases that bundle many changes together.
Feature flags break this coupling. By wrapping new code paths behind conditional checks, teams can deploy code to production without exposing it to users. The feature is then progressively released to increasing percentages of users while monitoring for errors, performance degradation, or negative user feedback. This approach, known as progressive delivery, transforms deployments from high-stakes events into routine operations.
How Feature Flags Work
At their simplest, feature flags are boolean values that control which code path executes. A conditional check queries the flag's state and branches accordingly. When the flag is off, the existing behavior runs. When the flag is on, the new behavior takes over.
In practice, feature flags are more sophisticated than simple booleans. Modern flag systems support targeting rules that determine which users see the new behavior based on attributes like user ID, geographic location, subscription tier, or any custom attribute. A flag might enable a new checkout flow for 10% of users in the United States while keeping the existing flow for everyone else.
The flag evaluation happens at runtime, meaning changes take effect immediately without redeployment. This is the critical distinction between feature flags and environment variables or build-time configuration: flags can be toggled in seconds, while configuration changes typically require a deployment.
Types of Feature Flags
Release Flags
Release flags gate features that are code-complete but not yet ready for all users. They are the most common type and typically have a short lifespan. Once a feature is fully rolled out, the flag and its conditional code should be removed. Release flags that linger indefinitely become technical debt.
Experiment Flags
Experiment flags support A/B testing by routing users into control and treatment groups. They integrate with analytics platforms to measure the impact of different implementations on key metrics. Unlike release flags, experiment flags are intentionally long-lived, running for the duration of the experiment.
Operational Flags
Operational flags act as circuit breakers or kill switches. They allow teams to disable features that are causing production issues without deploying a rollback. A flag wrapping a call to a third-party service can instantly fall back to cached data if the service degrades. Operational flags are permanent infrastructure.
Permission Flags
Permission flags control access to features based on entitlement. Premium features, beta access, and internal tools are gated behind permission flags tied to user attributes or subscription status. These flags are part of the application's authorization model rather than the release process.
Progressive Delivery in Practice
Progressive delivery uses feature flags as the mechanism for gradually exposing changes to wider audiences. A typical progressive delivery pipeline follows stages.
Stage 1: Internal Testing
The flag enables the feature only for internal team members. Developers and QA engineers exercise the feature in the production environment with real data and real integrations, catching issues that staging environments miss.
Stage 2: Canary Release
The flag targets a small percentage of production traffic, typically 1-5%. Monitoring dashboards compare error rates, latency, and business metrics between the canary group and the control group. If metrics degrade, the flag is turned off immediately.
Stage 3: Graduated Rollout
Confidence builds through incremental increases: 10%, 25%, 50%, 75%, 100%. At each stage, the team evaluates metrics and decides whether to proceed, hold, or roll back. Some teams automate this progression, advancing to the next stage if metrics remain healthy for a defined period.
Stage 4: Cleanup
Once the feature reaches 100% and has been stable for a sufficient period, the flag is removed from the code. The old code path is deleted. This step is crucial and often neglected; stale flags accumulate into a confusing web of conditional logic.
Feature Flag Architecture
Implementing feature flags well requires thoughtful architecture. The two primary approaches are client-side evaluation and server-side evaluation.
In client-side evaluation, the application downloads the full set of flag rules and evaluates them locally. This minimizes latency since no network call is needed for each flag check. However, flag rules must be synchronized periodically, and sensitive targeting logic is exposed to the client.
In server-side evaluation, each flag check makes a call to the flag service. This provides real-time evaluation and keeps targeting rules secure, but adds network latency and creates a dependency on the flag service's availability.
Most mature implementations use a hybrid approach: server-side evaluation with aggressive caching and streaming updates that push flag changes to application instances in near real-time.
Tools and Platforms
The feature flag ecosystem offers options across the complexity spectrum.
- LaunchDarkly is the most comprehensive commercial platform, supporting real-time streaming, sophisticated targeting, experimentation, and enterprise governance features.
- Unleash is a popular open-source alternative with a hosted option. It covers most use cases and integrates with major frameworks.
- Flagsmith offers both open-source and hosted versions with remote configuration capabilities beyond boolean flags.
- PostHog bundles feature flags with product analytics and A/B testing in a single platform.
- Custom implementation: For simple use cases, a database table of flag names and boolean values with a thin evaluation layer can work. However, this approach quickly becomes insufficient as targeting rules grow complex.
Best Practices
- Name flags descriptively: Use names like enable-new-checkout-flow rather than flag-123. Include the team or feature area for clarity in large organizations.
- Set expiration dates: Every release flag should have a planned removal date. Some platforms support automatic alerts when flags exceed their expected lifespan.
- Test both paths: Automated tests should cover both the flag-on and flag-off code paths. A flag that cannot be safely toggled off is not providing the safety net it promises.
- Limit flag scope: Keep the code surface area affected by each flag as small as possible. A flag wrapping an entire page is harder to reason about than a flag wrapping a specific component.
- Monitor flag usage: Track which flags are evaluated, how often, and by whom. Unused flags and over-evaluated flags both signal potential issues.
Feature flags and progressive delivery shift the risk of software releases from deployment time to controlled, observable, reversible rollouts. The initial investment in flag infrastructure pays for itself with the first major incident that a flag toggle resolves in seconds rather than a rollback resolving in minutes or hours.