Feature flags are conditional switches that turn features on or off at runtime without shipping a new build. A flag separates deploying code from releasing it: the feature ships dark inside the binary, then you enable it for specific users, a percentage rollout, or everyone, and disable it just as fast.
What are feature flags?
Feature flags (also called feature toggles) are runtime conditions wrapped around code paths. The new checkout flow ships inside your app binary, but a flag decides whether any given user sees it. Flip the flag and behavior changes across your install base without anyone downloading anything.
The idea, laid out in Pete Hodgson's article on feature toggles on martinfowler.com, is to separate two things that mobile development normally welds together: deploying code and releasing features. Deployment becomes a routine engineering event that happens whenever a build ships. Release becomes a product decision made later, per audience, and reversible within seconds for connected users.
That reversibility matters more on mobile than on the web. A web team that ships a bad feature deploys a fix in minutes, while a mobile team is stuck with what's installed on user devices until a new binary clears review and users update. In your release management toolkit, a flag changes app behavior faster than any of that.
How do feature flags work?
A feature flag system has three parts. A management service stores each flag's rules: who gets the feature and at what percentage, per environment. An SDK inside the app fetches the flag values for the current user and caches them. And in your code, a conditional checks the flag and picks a path.
The evaluation flow on a mobile device runs like this:
- The app starts and the flag SDK initializes with a user context (ID, device attributes, custom properties).
- The SDK gets flag values for that context and caches them locally. LaunchDarkly's mobile SDKs send the context to the service, which evaluates the targeting rules and returns only the results, so the rules never reach the device. Some vendors, including Optimizely and Split, download the ruleset instead and evaluate it on the device.
- Code asks the SDK for a flag's value; the SDK answers from its local cache without making a network call.
- When the device is offline or the fetch fails, the SDK falls back to values cached from a previous launch, and beyond that to the defaults compiled into the binary.
Every flag check includes a fallback value. That fallback is what a user gets if they open a fresh install with no connection, before the SDK has fetched anything. Here's what that looks like with the LaunchDarkly Android SDK:
// LDClient.init() has already run at app startup (e.g. in
// Application.onCreate); LDClient.get() returns that instance.
// The second argument is the fallback: what the user gets when
// no fresh or cached flag values are available (e.g. offline)
val client = LDClient.get()
if (client.boolVariation("new-checkout-flow", false)) {
launchNewCheckout() // flag on: the dark-shipped feature
} else {
launchLegacyCheckout() // flag off, or offline fallback
}
Why feature flags matter for mobile development
On mobile, you can't take a release back. Once a binary is on devices, you have up to three ways to change its behavior: a new release, an OTA update (for React Native and other JavaScript-based apps), or a flag. Only a flag reaches every version you've shipped it in without a new download. Apps that are open and connected see the change within seconds, and the rest pick it up on their next launch.
A web team reverts a bad deploy on servers it controls. On mobile, the App Store and Google Play offer no binary rollback. You can halt a staged rollout or pause a phased release so no new users get the bad build, but devices that already have it keep it until a replacement clears review and users update. A kill-switch flag around a risky feature means "roll back" becomes a config change instead of a hotfix.
Flags also unlock progressive delivery on a platform that resists it. Store-level staged rollouts control who gets the binary; flags control who gets the feature, per user, per market, per percentage, adjustable mid-release. Decoupling those lets mobile teams ship on the cadence DORA associates with strong delivery performance, where elite performers deploy on demand rather than in big, risky batches.
Flags are standard practice at scale: LaunchDarkly alone reports 45 trillion feature flags evaluated daily. Most experimentation tools are flag systems underneath, so flags are also how mobile teams run A/B tests during a mobile release without shipping separate builds.
Feature flags best practices
Flag problems tend to show up months after launch, as stale flags pile up and old app versions keep checking flags nobody remembers. Most of the practices below deal with that lifecycle: who owns a flag and when it goes away.
1. Make every fallback value the safe path. The default you compile into the flag check (boolVariation("flag", false)) is what users get when the SDK has no fetched or cached value to fall back on. It should always select the proven behavior, never the new feature. If a flag's fallback is true, offline users get the new feature even after you've switched it off, and your kill switch can't reach them.
2. Give every flag an owner and an expiry. Create the cleanup ticket in the same PR that adds the flag, and record whether the flag is temporary (a release gate) or permanent (an operational kill switch). Temporary flags that outlive their feature turn into dead code that's risky to delete.
3. Remember old versions never stop evaluating. The install base runs every version you've shipped, so a flag referenced by a two-year-old build is still live infrastructure. Before deleting a flag, confirm the versions that check it have fallen below your support threshold, and leave the fallback path working for the ones that remain.
4. Test the combinations you actually ship. Two flags create four states; your test matrix should cover the states real users will hit, especially "everything off", which is what a fresh offline install gets. Wire the high-risk combinations into your mobile app testing workflow rather than testing only the happy path with everything on.
5. Wrap risky subsystems in kill switches deliberately. Payments, sync, anything touching third-party APIs: give each a permanent, documented flag with an owner and a runbook line saying when to pull it. During an incident, a kill switch turns a feature off for connected users within seconds, hours before the fastest emergency release could.
Feature flags vs remote config
Mobile developers meet both tools early, often through the same SDK, and the boundary is blurry because each can technically impersonate the other. The clean split: remote config tunes values inside a feature, while feature flags decide whether the feature exists for a given user at all.
Starting with remote config as a makeshift flag system works, for a handful of booleans. It breaks down at targeting and lifecycle. Per-user targeting and overrides, kill-switch workflows, tracking which temporary flags are stale and safe to delete: those are the parts you don't want to homegrow twice.
How Bitrise handles feature flags
Bitrise connects feature flags to the place mobile teams make release decisions: Release Management integrates with LaunchDarkly, so the flags that gate your features are visible in the context of each release you're rolling out.
The setup is two connections. First, link accounts: in your Bitrise profile menu, open Account settings and choose Feature flags in the sidebar, then use the Connect button in the LaunchDarkly section to authorize access. Then, point an app at a project: under Releases, pick your app from the Connected apps list and open Feature flags, then use the Change control in the Project and environment section to select the LaunchDarkly project and environment that app uses, then save. From then on, each release of the app shows the feature flags of that project. The integration documentation walks through both steps with screenshots.
Flags in the release view solve an operational problem. A staged rollout is two rollouts moving together: the binary percentage in the store and the flag percentages inside it, and a release manager deciding whether to promote from 10% to 50% needs to see both. Flag visibility next to the release removes the tab-switching and the guesswork about which environment's rules apply to the build going out. Release Management handles the store side, including staged rollouts, release status and approvals.
Flags and OTA updates also divide the work cleanly on Bitrise. CodePush changes the code installed on devices; flags change which of the already-installed code paths run. A React Native team will often use both from the same platform: CodePush to deliver the fix or feature dark, then a flag to release it audience by audience. Because both run alongside your mobile CI/CD workflows, the whole path from merged PR to progressively released feature stays in one place.
See what Bitrise can do for you
Confidently build, test, and ship high-quality mobile apps with Bitrise.
Author
Frequently Asked Questions
What is the difference between a feature flag and a feature toggle?
Nothing; they're two names for the same mechanism. "Feature toggle" is the older term, popularized by Martin Fowler's writing; "feature flag" is what most vendors and teams say now. You'll also see "feature switch" and "feature gate", and all four describe a runtime condition that turns a code path on or off.
Do feature flags slow down my app?
Not meaningfully when used as designed. Flag SDKs answer from locally cached values, so a flag check is an in-memory lookup, not a network call. The costs show up elsewhere: SDK initialization on startup, the size of the flag payload you fetch, and the testing effort as code paths multiply.
What are feature flags on iPhone?
Two unrelated things share the name. The Feature Flags menu on an iPhone (Settings > Apps > Safari > Advanced) toggles experimental WebKit features for web developers. In app development, feature flags are the runtime switches described in this article, which your app evaluates through an SDK. Seeing a Feature Flags menu on an iPhone doesn't mean an app's product flags are exposed there.
How long should a feature flag live?
Remove a release flag's check from your code within weeks of reaching 100% rollout. Keep the flag itself switched on in the dashboard until the app versions that still check it fall below your support threshold. Kill switches and operational flags are the exception and live as long as the subsystem they guard, with an owner and documentation. The habit that keeps a codebase healthy is scheduling a flag's removal on the day it's created.

