2026-05-02
Feature flags without chaos
A minimal system for safe rollout, experiments, and fast rollback.
Flags are great until they turn into permanent complexity. Teams add them for safety, then forget to remove them, and soon every code path has three conditional branches. We keep them healthy by defining ownership, expiration dates, and a small set of flag types with clear semantics.
The key is treating rollout as a system: staged exposure, monitoring gates, and a default rollback path. If a flag can’t be turned off safely, it’s not really a safety mechanism—it’s just hidden risk. Make “off” the tested default, and rehearse rollback like you rehearse incident response.
Done well, flags reduce risk and speed delivery — without leaving the codebase full of dead branches. They also enable smaller pull requests because you can merge incomplete work behind a flag and decouple shipping from releasing.
Treat flags like inventory: every flag has an owner, a purpose, and an expiry date. If you can’t answer those, the flag is already a liability. A simple monthly review (what’s active, what’s stale, what’s safe to delete) prevents long-term accumulation.
Prefer a small set of flag types (rollout, experiment, kill-switch). Keep targeting rules simple and observable, and log evaluations only where it helps debugging. If targeting becomes complex, move it into a dedicated system with tests—otherwise you’ll create a second, unreviewed policy engine inside your app.
Finally, schedule flag cleanup as part of delivery. The fastest teams delete flags aggressively once risk is retired. Cleanup is not optional housekeeping; it’s the cost of keeping the system simple enough to move quickly next quarter.
