Feature Flags for High-Stakes Features
Why we gate every booking and payment change behind a feature flag, and how we manage the flag lifecycle — percentage rollouts, kill switches, and cleanup.

We shipped a payment change that broke 3D Secure verification for about 2% of users. The change looked fine in testing. It passed staging validation. It worked for 98% of payment methods. But a specific combination of card issuer and device type triggered a flow our test coverage didn't hit.
Without a feature flag, fixing this would have meant: identify the bug, write a fix, push through the full deployment pipeline, and deploy. Minimum 30 minutes, probably more. During that time, 2% of travelers trying to book were hitting payment failures.
With a feature flag, the fix was: turn off the flag. Ten seconds. Old payment logic reactivated. Travelers could book again. Then we fixed the bug properly, re-deployed, and gradually re-enabled the flag.
That experience is why every booking and payment change now goes behind a flag. No exceptions. The cost of maintaining the flag is trivial. The cost of not having it during an incident is measured in lost bookings and damaged trust.
Risk categorization

Not every change needs a feature flag. A copy change in the help text doesn't need a kill switch. A new profile settings option doesn't need a percentage rollout. The overhead of flag management is small but non-zero, and flagging everything would create flag fatigue.
We categorize changes by risk:
Must flag. Any change to the booking flow, payment processing, AI agent behavior, or notification delivery. These are the paths where bugs have direct financial or trust impact.
Should flag. Changes to search result ranking, trip display logic, or data model queries. These affect user experience but don't directly involve money or security.
No flag needed. UI styling changes, copy updates, new non-critical features, internal tooling changes. Ship directly.
The categorization is enforced in code review. If a pull request touches files in the booking or payment paths, the reviewer verifies that a feature flag is present.
Percentage rollouts
When we enable a flagged feature, we don't go from 0% to 100%. We ramp up gradually.
1% rollout. A tiny fraction of traffic hits the new code path. We watch for errors, latency increases, and unexpected behavior. At this scale, even a significant bug affects very few travelers.
10% rollout. If 1% looks clean, we increase to 10%. This is where we start getting statistically meaningful data. Are booking success rates the same for the flagged group as the control? Is payment processing time comparable?
50% rollout. Half the traffic runs the new path. This is a true A/B test. We can compare metrics between the two groups with confidence. If the new path is better (higher booking completion, faster processing), we see it here.
100% rollout. Full rollout. The flag is still active (in case we need to kill it), but all traffic runs the new path.
Each step has a minimum duration. We don't ramp from 1% to 10% in 5 minutes even if everything looks fine. We let each step run long enough to encounter the daily traffic pattern, including different geographies, time zones, and device types. A bug that only manifests for a specific mobile browser in a specific region might take hours to appear.
Kill switches

The most important property of a feature flag is that it can be turned off instantly. Not "in the next deploy." Not "after a restart." Instantly.
Our flag system supports this through runtime evaluation. The flag state is checked on each request, not baked into the container at build time. When an operator flips a flag, the next request evaluates the new state. No deployment, no restart, no cache flush needed.
Kill switches have saved us multiple times. Not always from bugs. Sometimes an external dependency changes behavior in a way that interacts badly with our new code. Sometimes a specific traffic pattern exposes an issue we didn't anticipate. The ability to revert to the old behavior in seconds provides a safety net that makes the team more confident about shipping changes.
Flag cleanup and tech debt
Feature flags that live too long become landmines. The code has two paths: the old one and the new one. Both need to be maintained. Both need to be tested. Both need to be understood by new team members. Over time, the old path becomes stale. Nobody remembers exactly what it does. But nobody dares remove it because "what if we need to roll back?"
We enforce a flag lifecycle:
Create. The flag is created when the feature branch is ready for deployment. The flag starts at 0%.
Rollout. Gradual percentage increase over days or weeks.
Full-on. The flag is at 100% and has been stable for at least two weeks.
Cleanup. The old code path is removed. The flag check is removed. The code simplifies back to a single path.
The cleanup phase has a deadline. Two weeks after reaching 100%, the flag must be cleaned up. If the team hasn't cleaned it up, the flag appears on our tech debt dashboard as overdue.
This discipline prevents flag accumulation. At any given time, we have a handful of active flags for in-progress rollouts, not dozens of abandoned flags from past experiments.
Measuring impact through flags
Feature flags aren't just safety mechanisms. They're measurement tools. By routing some traffic to the new path and some to the old, we get clean comparisons.
When we changed our flight search result ranking, the feature flag let us measure: do travelers book faster with the new ranking? Do they click on more options? Do they convert at a higher rate? The data from the flagged rollout informed whether the change was an improvement, not just whether it was safe.
This turns feature flags into an experimentation platform. Ship the change, measure the impact, and decide whether to keep it based on data. The alternative, shipping changes and hoping they're better, works fine for low-stakes features but is reckless for the booking path where every percentage point of conversion rate matters.
The minimum viable flagging system
If you're adding feature flags to your payment path:
Start simple. A flag is a boolean checked at runtime. Don't over-engineer the flag system. A configuration file or database table that maps flag names to boolean values is enough to start.
Support percentage rollouts. Even a simple hash of the user ID modulo 100 gives you percentage-based routing. No need for a sophisticated targeting engine on day one.
Make kill switches instant. The flag evaluation must be runtime, not build-time. If turning off a flag requires a deploy, it's not a kill switch.
Enforce cleanup. Set a policy for how long flags can live. Track overdue flags. Make cleanup a regular part of the development cycle, not an afterthought.
Flag the dangerous stuff, not everything. Flagging a copy change adds overhead without meaningful risk reduction. Flagging a payment flow change could save you from a multi-hour incident. Be selective about what gets flagged.
Nowah is an AI travel agent that searches and books real flights and hotels through conversation — no filters, no thirty open tabs. Plan your next trip.