Feature flags vs OTA updates: you need both, but not for the same job
Flags toggle code you already shipped; OTA ships code you haven't. Teams that conflate the two either over-flag their codebase or under-use their update channel. Here is the clean division of labor.
A question we hear from teams setting up their release stack: "we already have LaunchDarkly/Statsig — do we still need OTA updates?" And its mirror image: "we have OTA — can we skip the flag service?" Both questions treat the tools as substitutes. They're not. They operate on different objects, and the confusion dissolves the moment you name them.
The one-line distinction
A feature flag changes which of your already-shipped code paths runs. An OTA update changes what code is on the device at all. Flags select; OTA delivers. Everything else follows from that.
What flags are unbeatable at
- Decoupling launch from deploy. Merge dark, ship in the release train, flip the flag on launch day — marketing-coordinated launches without release-day deploys.
- Experimentation. A/B tests, gradual exposure by audience segment, percentage holdbacks. This is what flag platforms are actually built around.
- Instant-ish reversal of anticipated risk. If you predicted a feature might misbehave and gated it, turning it off is one click and no build. One caveat mobile teams learn the hard way: most mobile flag SDKs poll rather than stream, so "instant" is really "within minutes, for apps that are foregrounded" — plan kill switches around that latency.
What flags fundamentally cannot do
A flag can only disable what you wrapped in a flag. The bug that actually bites you on a Friday is, almost by definition, in code nobody thought to gate — a crash in the checkout flow, a broken regex, a null deref on a screen that's been stable for a year. There is no flag for that. Your options are a store release (days of latency, multiplied by review-time variance) or an OTA update that replaces the code itself in hours. This is the core case for having an update channel at all: flags mitigate the risks you predicted; OTA fixes the ones you didn't.
What OTA shouldn't be used for
Symmetry demands the other list. Using OTA updates as a flag system — shipping a new bundle to turn a feature on for 10% of users, another to turn it off — technically works and is operationally clumsy: every toggle is a release, your release history fills with configuration noise, and experiment analysis has no clean exposure tracking. If you're toggling by audience and measuring outcomes, that's a flag platform's job. There's also a compliance angle: OTA is for iterating on your reviewed app. Apple's review guidelinesprohibit downloaded code that changes an app's features or functionality, so a policy-sensitive release needs its own review — gate big new features through a store release, then iterate on them over the air.
The stack that works in practice
- New feature: ship dark in the release train, behind a flag. Launch by flipping the flag. Iterate on the feature's JS via OTA once it's live.
- Unanticipated bug: fix in JS, ship OTA behind a staged rollout, done the same day.
- Anticipated risk: kill switch flag, with the polling latency understood.
- Config and copy churn: remote config if it's data, OTA if it's logic. If you find yourself encoding behavior into JSON that a generic engine interprets, you've reinvented server-driven UI — sometimes correctly, so read that post before you commit.
Two tools, two objects, no rivalry. The teams that get this right tend to have boring releases — which is the entire goal.