Feature Toggles in Mobile Apps: Implementation and Management
Martin Fowler: "Feature toggle is a technique that allows you to turn features on and off without deploying new code."
Feature toggle — a mechanism to enable/disable functionality without a new app release (see Feature Toggle). Sounds simple, until you start thinking about client versions, flag caching, graceful degradation when the server is unavailable, and the accumulated graveyard of dead flags a year later. This is where most teams make critical mistakes that lead to tech debt and performance degradation.
We have been implementing flags in mobile projects for over 6 years. During this time, we have built systems for 50+ apps — from startups to enterprise with millions of users. Our experience shows that proper flag architecture reduces release time by 30% and the number of critical bugs in production by 40%. The average budget saving on testing is 30%.
Why flags are needed in a mobile app
Trunk-based development. A developer merges an unfinished feature into main under a flag — CI/CD works normally, QA doesn't see raw code, in production it's disabled. Long-lived feature branches with merge conflicts after three weeks are a thing of the past.
Gradual rollout. A new feature is first enabled for 1% of users → 10% → 50% → 100%. If Crashlytics shows an increase in crashes, the flag is turned off instantly, without revoking the release.
A/B tests. One button is green, another is blue. A flag with variations, analytics show which converts better.
Kill switch. A payment provider goes down — we disable the payment screen and show a placeholder. Without a hotfix or App Store Review.
Implementation options
Firebase Remote Config — de facto standard for most mobile apps. Free, SDK for iOS/Android/Flutter/React Native, personalization by user properties (country, app version, segment). Downside: not suitable for enterprise with strict data storage requirements.
LaunchDarkly — enterprise solution with targeting rules, A/B tests, change audit, SSO. Expensive, but if the team has 50+ developers and hundreds of flags — justified.
Custom service — when you need full control or cannot send user data to third-party servers. Go/Node/Laravel backend, PostgreSQL for flag storage, Redis for cache, WebSocket or polling for real-time updates.
Unleash — open source alternative to LaunchDarkly, self-hosted. SDK for all platforms, targeting, gradual rollout. Good balance between functionality and control.
| Tool | Free | Enterprise features | Self-hosted |
|---|---|---|---|
| Firebase Remote Config | Yes | No | No |
| LaunchDarkly | Trial | Yes | No |
| Unleash | Partially | Yes (via paid plugins) | Yes |
| Custom service | Depends | Full control | Yes |
How to implement feature toggles in 5 steps
- Audit the current architecture: determine which flags are needed (rollout, kill switch, A/B).
- Choose the tool: evaluate Firebase Remote Config, LaunchDarkly, or a custom service.
- Design categories of flags, default values, rollout probabilities.
- Integrate SDK on the client and server, implement caching.
- Write tests and documentation, train the team.
Why feature toggles are better than feature branches?
Compare: a long-lived branch lives for 3-4 weeks — during that time, main moves 5 commits ahead with conflicts. A feature toggle merges in one day, no conflicts, code is always up to date. In our experience, teams using trunk-based with flags release 2 times more often.
Technical implementation on the client
Key rule: flags must work without a network. On first launch — default values from the bundle, subsequently cached in UserDefaults/SharedPreferences, updated from the server in the background.
iOS (Swift):
// FeatureFlagService with caching actor FeatureFlagService { private var flags: [String: Bool] = [:] func isEnabled(_ flag: FeatureFlag) -> Bool { flags[flag.rawValue] ?? flag.defaultValue } func refresh() async { // Load from Remote Config or custom API let fetched = await remoteConfigService.fetch() flags = fetched } } // Usage in SwiftUI if featureFlagService.isEnabled(.newCheckoutFlow) { NewCheckoutView() } else { LegacyCheckoutView() } Android (Kotlin): similarly via StateFlow in ViewModel so that UI reacts to flag changes in real-time without restarting the screen.
How to avoid accumulation of dead flags?
The main operational issue: flags accumulate. After a year, if (featureFlags.isEnabled("new_onboarding_v2")) in the code is a dead flag that no one will remove because it's unclear what will happen. The code becomes unreadable, tests don't cover both branches.
Process: each flag is created with a planned deletion date (e.g., 90 days after rollout). After full rollout — a task to remove the flag and the unnecessary code branch. Tool: ArchUnit (Android) or static analysis (SwiftLint custom rule) to detect expired flags in CI.
What to do if the flag server is unavailable?
We use two-level caching: on startup, the app takes flags from the bundle, then loads from Remote Config and saves locally. If the server is unavailable — the flag remains current until the next successful request. Graceful degradation is implemented via defaultValue, disabling non-critical features while critical functionality works in a stable mode.
Additional advantage
Comparison: Firebase Remote Config vs LaunchDarkly
Firebase Remote Config is configured 3 times faster than LaunchDarkly, but LaunchDarkly is 5 times more reliable for enterprise in terms of compliance. The choice depends on scale: for 10 developers, Firebase is enough; for 100, LaunchDarkly.What is included in the work
- Audit of the current mobile app architecture
- Design of the flag system (categorization, default values, rollout probabilities)
- Backend setup (Firebase, LaunchDarkly, Unleash, or custom service)
- SDK integration on the client (iOS/Android/Cross-platform)
- Writing unit tests and UI tests for flags
- Documentation on adding new flags and their lifecycle
- Training the team on flag usage
- Support for 2 months after implementation
| Process | Timeline |
|---|---|
| Firebase Remote Config integration | 2–3 days |
| Custom feature-flag service | 3–4 weeks |
| Migration from branches to flags | 1–2 weeks |
Timeline: from 2 days to 4 weeks depending on complexity.
Contact us for an audit of your project — we'll help you set up flexible feature management without unnecessary risks. Get a consultation from an engineer with 6+ years of experience in mobile development. Book a free review of your flag system.







