Architecture
Feature Flags
Decoupling deployment from release by toggling features at runtime without a redeploy.
Overview
Feature flags (also called feature toggles) decouple software deployment from feature release. New code is deployed to production but kept inactive until a flag is enabled. Flags allow gradual rollouts, A/B tests, instant rollbacks without redeployment, and targeting specific users or environments.
Origin
Feature flags became prominent through continuous delivery practices popularised by Jez Humble and David Farley in "Continuous Delivery" (2010). Services like LaunchDarkly (founded 2014) built businesses around flag management infrastructure.
Examples
Flag-gated feature rollout
import { FeatureFlags } from './flags'
// Simple boolean flag
if (FeatureFlags.enabled('new-checkout-flow', { user })) {
return renderNewCheckout(cart)
} else {
return renderLegacyCheckout(cart)
}
// Percentage rollout (stored in config or LaunchDarkly)
class FeatureFlags {
static enabled(flag, context = {}) {
const config = this.getConfig(flag)
if (!config || !config.enabled) return false
// Percentage rollout: hash userId for consistent assignment
if (config.rolloutPercent < 100) {
const hash = murmurhash(context.user?.id + flag) % 100
return hash < config.rolloutPercent
}
return true
}
}
// Usage: graduated rollout
// Week 1: rolloutPercent: 5 (5% of users)
// Week 2: rolloutPercent: 25
// Week 3: rolloutPercent: 100 (everyone)
// Remove flag from code once stableUse Cases
- 01Gradual rollout: expose a new feature to 1%, then 10%, then 100% of users
- 02Kill switches: instantly disable a broken feature without a deploy
- 03A/B testing: different users see different implementations for experimentation
- 04Beta programs: enable features for specific users or accounts only
- 05Operational flags: enable debug logging or maintenance mode at runtime
When Not to Use
- //Flags accumulate technical debt, every flag is a code branch that must be maintained. Remove flags once rollout completes
- //Security-sensitive code should not be flag-gated, authentication and authorisation must always be on
- //Complex flag interdependencies create combinatorial test cases that become unmanageable
Technical Notes
- Flag debt is real: Netflix and Facebook have written about the maintenance cost of hundreds of long-lived flags. Treat flags like branches, merge and delete promptly
- Use consistent hashing for percentage rollouts: the same user must always see the same variant to avoid flickering
- Flags should be defined in one place (a service like LaunchDarkly or a config file) and never duplicated across codebases
- Test both paths of every flag, the non-flag path must continue to work after the flag is removed
More in Architecture
SOLID PrinciplesDesign PatternsClean & Hexagonal ArchitectureSeparation of ConcernsDependency InjectionEvent SourcingCQRSRepository PatternStrangler Fig PatternMicroservicesLoad BalancingMessage Queues & Pub/SubDistributed SystemsCAP TheoremDatabase Sharding & ReplicationAPI Gateway PatternService MeshCircuit Breaker PatternSaga PatternBlue-Green DeploymentCanary ReleasesServerless Architecture