Feature flags, sometimes called feature toggles, let development teams ship code to production without immediately exposing it to every user. The idea is simple: wrap a new behaviour in a conditional check, control that check from a config store or management platform, and switch the feature on or off without redeploying. In practice, that simplicity hides a fair amount of operational complexity, and Australian teams that adopt flags without a clear governance model tend to accumulate dead toggles faster than they ship features.
Why feature flags matter for continuous delivery
The core problem flags solve is the tension between trunk-based development and safe releases. When every developer commits directly to main, code reaches production frequently. That's good for velocity. It's dangerous when a half-built feature goes live with it. Feature flags are the mechanism that breaks the link between "deployed" and "live."
This matters especially in teams running CI/CD pipelines, where code can go from commit to production in minutes. Without flags, the only way to keep unfinished work out of users' hands is long-lived branches, which reintroduce the merge conflicts and integration pain that continuous delivery was meant to eliminate. Flags give you trunk-based development without the exposure risk.
Three concrete use cases dominate:
- Progressive rollouts. Enable a feature for 1% of users, watch your error rates and latency, then ramp to 10%, 50%, and full release. If anything goes wrong, you toggle off rather than roll back a deployment.
- Kill switches. Production incidents are contained by flipping a flag rather than triggering a hotfix pipeline. This cuts mean time to recovery dramatically for feature-level failures.
- A/B testing. Different user cohorts see different variants simultaneously, letting product teams measure real behaviour rather than guessing.
The flag types you need to know
Not all flags work the same way. Martin Fowler's taxonomy from the ThoughtWorks blog describes four categories, and conflating them is where teams go wrong.
Release flags are short-lived by design. They gate an incomplete feature in progress and should be deleted within days or weeks of the feature going fully live. These are the most common type and the most commonly left to rot.
Experiment flags power A/B and multivariate tests. They live longer than release flags but should have a clear sunset date tied to statistical significance. Once the experiment concludes, the losing variant's code and flag get deleted.
Ops flags control operational behaviour: circuit breakers, rate limiters, feature kill switches for high-load events. These can be permanent fixtures. They're justified long-term because they give ops teams real-time control over production behaviour without a code change.
Permission flags expose features to specific users or plans, like a beta programme or a premium tier. These also tend to be permanent and belong in your entitlements or billing system more than in a feature flag service.
The flag debt problem
Flag debt is real and it compounds. A codebase with 200 active flags is significantly harder to reason about than one with 20. Nested flag conditions create combinatorial complexity: if flag A and flag B are both active, what actually runs? Engineers who weren't around when a flag was created are afraid to delete it. Flags accumulate. Tests multiply to cover every combination.
This is the same structural problem as technical debt more broadly: the cost is invisible until it isn't, and by then the cleanup effort is enormous. The discipline required is proactive, not reactive.
Set a maximum flag lifespan at creation time. Release flags should expire in 30 days. Add a Jira ticket (or equivalent) to remove the flag when you create it, not after the feature ships. Some teams use automated scanning tools to alert when a flag exceeds its expiry without being cleaned up. LaunchDarkly, Unleash, and Flagsmith all support expiry metadata for this reason.
Targeting and rollout strategy
A flag that's either fully on or fully off is a blunt instrument. Modern flag platforms let you target by user attribute, session property, geographic region, or account tier. This granularity is what makes flags genuinely powerful for Australian teams serving distinct market segments.
A practical rollout sequence for a new feature looks like this. Start with internal users only, typically your own company's accounts or a dedicated test organisation. This surfaces obvious bugs without customer exposure. Move to a closed beta: opt-in users who've agreed to test early features. Then a percentage rollout starting at around 5%, watching your observability dashboards for error rate spikes. Full release happens only when the metric picture is clean.
The targeting logic should live in the flag platform, not in your application code. Hard-coding user IDs or conditions in your codebase defeats the purpose. If your flags are just if (userId === "123") conditions scattered through the source, you've built a different kind of technical debt.
Observability and flags
Flags are only useful if you can tell what effect they're having. Every flag evaluation should be traceable. When a user reports a bug, you need to know exactly which flags were active for their session at that moment. Without that context, reproduction is guesswork.
Good flag platforms emit evaluation events that you can feed into your observability stack. Correlating flag state with your existing metrics, traces, and logs turns a flag flip from a blind action into a measured intervention. If you're not yet correlating flag evaluations with your error rates and latency distributions, you're flying partially blind. This integrates naturally with the broader observability practice most mature teams already have in place.
Choosing a flag management tool
Rolling your own flag system is a valid starting point. A database table with flag names and boolean values works for small teams. It stops working when you need targeting rules, audit logs, percentage rollouts, and SDK support across five languages. At that point, a managed platform is worth the cost.
LaunchDarkly is the market leader and the most feature-complete option, with strong SDK coverage and enterprise controls. It's priced for enterprise and reflects that. Unleash is the leading open-source alternative, self-hostable, and a good fit for teams with data sovereignty requirements or tight budgets. Flagsmith is another open-source option with a generous hosted free tier. Smaller teams using AWS should also look at AWS AppConfig, which handles feature flags alongside application configuration inside the AWS ecosystem.
The right choice depends less on the platform's feature list and more on where your team's operational effort can afford to go. Self-hosting Unleash is free in licence cost but not in maintenance cost. LaunchDarkly is expensive but zero-ops. Make that trade-off deliberately.
Testing with flags active
Every flag permutation that can reach production needs a test. This sounds obvious and is routinely ignored. Teams write tests for the "flag on" path, ship the feature, and quietly forget that the "flag off" path also runs in production for 95% of users during rollout.
A workable approach is to parameterise your test suites so that flag-dependent tests run with the flag both on and off. Integration tests should cover both states. End-to-end tests should cover at minimum the default state (flag off) and the target state (flag on). If the combination space is too large to test exhaustively, that's a signal you have too many flags active simultaneously in overlapping parts of the system.
Flag testing is also where your CI/CD pipeline becomes critical. The pipeline should fail if a flag-dependent test breaks in either state. That discipline is what prevents the "it worked in staging" problem that comes from only ever testing the fully-enabled configuration.
Security and access control
Feature flag platforms are infrastructure, not just tooling. They sit in the critical path of production behaviour. A compromised flag platform can enable or disable security controls, expose unfinished code, or silently degrade user experience for targeted segments.
Treat your flag management system with the same access controls you'd apply to your deployment pipeline. Audit logs should be non-negotiable. Who changed a flag, when, and to what value should be answerable from the platform without contacting the person who made the change. Approval workflows for production flag changes make sense for high-impact toggles, particularly ops flags that control circuit breakers or rate limits.
For teams operating under Australia's Privacy Act requirements or handling sensitive data, check whether your flag platform stores user attribute data for targeting. Some hosted platforms process user identifiers server-side for targeting decisions, which has data residency implications. Unleash's client-side evaluation model avoids this entirely by keeping targeting logic in the SDK and never sending user data to the flag server.
A flag is not a config system
One antipattern worth naming directly: using feature flags to manage application configuration. Flags answer the question "should this feature be visible?" Configuration answers "what value should this setting have?" Mixing them turns your flag platform into a general-purpose config store, which it isn't designed to be. Keep flags for behaviour changes and use a proper secrets or config management tool for everything else. The cleaner that boundary is, the easier both systems are to reason about.
Teams that treat flags as config end up with hundreds of flags that never get cleaned up because nobody's sure whether they're controlling a feature or a production value that something depends on. That ambiguity is the root cause of most flag debt problems.

