A calm look at feature flags
A calm look at feature flags
Feature flags (a.k.a. feature toggles) are a pattern frequently cited from large-company case studies. Small teams sometimes carry the same expectations into them, but cost and benefit vary by environment. This article organizes the facts.
1. About feature flags
A technique that places togglable switches at branching points in code, separating deployment from release. The code is deployed in production but only runs for specific users or conditions.
Representative tools:
- LaunchDarkly (2014, Edith Harbaugh and others) — SaaS. The most widely known commercial.
- Unleash (2014, originated at FINN.no) — open-source core. Self-hosting available.
- Flagsmith (2018) — open-source core + SaaS.
- Split (2015), GrowthBook (2020), PostHog (includes a feature flag module, 2020), etc.
Martin Fowler and Pete Hodgson's article "Feature Toggles (aka Feature Flags)" (2017) is frequently cited as the article that organized toggle classification.
2. Toggle classification
Hodgson's classification has four:
| Kind | Lifespan | Intent |
|---|---|---|
| Release toggle | Short (days to weeks) | Keep unfinished features in production code but disabled. Gradual release after merge. |
| Experiment toggle | Short | A/B testing. Different paths per user group. |
| Ops toggle | Variable | Temporarily block features during incidents (killswitch). |
| Permission toggle | Long | Feature exposure per user / plan. |
The operational cost differs per kind. Release toggles are best when short-lived, while permission toggles are essentially a permission system and should be handled differently.
3. Relation to Trunk-Based Development
trunkbaseddevelopment.com recommends feature flags for keeping unfinished features in trunk. Short feature branches + flag-gated unfinished code = frequent merges + safe releases.
Reasons this combination is often adopted in big-team CI/CD pipelines:
- The longer merging is delayed, the higher the conflict cost.
- Daily merges resolve conflicts in small units.
- A safety device is needed to hide unfinished features, hence flag adoption.
4. Cost / benefit in small teams
Feature flags add branches to code. Branches bring:
- Test matrix growth — one flag creates two paths, two flags create four paths.
- Code noise —
if flag.is_on('x') ...scatters everywhere. - Lifespan management — release toggles after release end need removal but are easily forgotten. The reason tools like LaunchDarkly provide "stale flag" notifications.
- Operational dependency — predetermine behavior when the flag-evaluation service dies. Usually a fallback value is hardcoded into the code.
For small teams (5 or fewer developers, low daily deploy frequency, small user base), the following often have equivalent effect:
- Short feature branches + PRs + fast merges.
- Simple toggles gated by one or two environment variables.
- Provide separate environments / domains for beta users.
If the rich features of large-scale tools (LaunchDarkly, Unleash) — targeting, segmentation, A/B statistics — go unused, cost-to-benefit shrinks.
Signs that the effect is clear in big teams:
- High daily deploy frequency (many per day).
- Many unfinished features merged into trunk simultaneously.
- Gradual release per user segment (canary, ring) is routine.
- Need to quickly cut features at incident time.
5. Other paths
Alternatives or complements to feature flags:
- Environment separation — distinction of dev / staging / prod. A simple per-environment toggle is often enough.
- Blue-green / canary deploys — gradual release at the infrastructure level. Doesn't increase code branches.
- Permission system — feature exposure per user / plan is clearer when handled by a domain-level permission model.
- Dark launch — place a new code path in production but don't show results to users; only compare data. Activate after verification.
6. Common shapes
Simple environment-variable based (small team):
const NEW_PRICING = process.env.FEATURE_NEW_PRICING === "1";
function priceFor(item) {
return NEW_PRICING ? newPrice(item) : legacyPrice(item);
}
Tool-based (LaunchDarkly-style SDK pseudocode):
const showNewPricing = await client.variation("new-pricing", user, false);
7. Common pitfalls
"Stale flag" accumulation — toggles left on and forgotten cover the codebase. When the two paths created per branch evolve in different directions, removing the toggle becomes risky.
Toggles standing in for a permission system — handle permissions through a domain model; restrict toggles to release, experiment, and incident shutoff.
Dependent toggles — when one toggle assumes another (B is meaningful only when A is on), the matrix explodes. Document dependencies between toggles explicitly or remove them.
Tool dependency — a temporary outage of an external SaaS prevents operational decisions. Determine cache and default-value handling from the start.
A small team importing big-team examples wholesale — tool cost (SaaS fees, operational burden) often outweighs benefits.
Closing thoughts
Feature flags clearly help in big-team CI/CD environments, but in small teams the code noise and operational dependency may exceed the benefit. The three traps of stale-flag accumulation + matrix explosion + permission-system substitution are common. Environment separation + simple environment variables + canary deploys — infrastructure-level separation — is the more natural place.
Next
- naming-readability
- (philosophy end)
Pete Hodgson · Martin Fowler Feature Toggles · LaunchDarkly official docs · Unleash official docs · Flagsmith official docs · Trunk-Based Development · Continuous Delivery (Humble & Farley, 2010) · GrowthBook official site · PostHog Feature Flags for reference.