Firebase series · Part 1 of 4

Firebase Remote Config: Change Your App Without a New Release

Khairul Alam·October 2026·~8 min read
FirebaseRemote ConfigAndroidFeature flags

Remote Config lets you change how your app looks and behaves from a console, without publishing a new version. It is a key-value store in the cloud that your app downloads and reads. This post is the overview; Google’s guide covers the exact setup.

In 60 seconds
  • What: cloud key-value settings your app fetches.
  • Use for: feature flags, kill switches, copy, limits, gradual rollouts.
  • Key idea: ship defaults in the app, override them from the console.
  • Watch out: values may arrive late. Fetch at launch and keep safe defaults.
  • Not for: secrets or user data. Values are readable by the app user.
Contents
  1. What it is
  2. How it works
  3. Timing: values are not instant
  4. Conditions and rollouts
  5. Common uses
  6. A tiny example
  7. Limits and good habits

1. What it is

Normally, changing a button colour or turning a feature off means a new build, a store review and users updating. With Remote Config the app reads its settings from Firebase instead. You edit a value in the console, publish, and the app picks it up on its next fetch.

Analogy. A TV remote for your app: the TV (your code) is already built, and the remote (console) changes channels and volume from a distance.

Remote Config · Parameters promo_banner_enabled true min_app_version 2.4.0 checkout_button_color #10b981 welcome_message Hello!
A sketch of the console’s Parameters tab: each row is a key with a default value, and can have conditions on top. (Illustration, not a screenshot.)

2. How it works

Your app ships with in-app defaults. On start-up it fetches the latest values from the service, then activates them so the code reads the new ones. Fetches are throttled, so the new value may appear on the next launch rather than instantly.

Firebase consoleyour rules Remote Configcloud App v1 (Android)fetch + activate App v2 (iOS)fetch + activate publish values
Change a value in the console, publish it, and apps pick it up on their next fetch. No store release.
In-app defaultsshipped in app Fetched valuesfrom server Active valueswhat code reads fetch activate Code always reads the active value; if nothing was fetched, the default is used.
The lifecycle behind every call: defaults, fetched, active. Nothing changes in the UI until you activate.

3. Timing: values are not instant

A fetch is a network call. On a slow connection, in airplane mode, or on the very first launch it may be late or fail, and the throttle can also hold back a refresh. If your code assumes the new value is already there, it can read the wrong one at the worst moment, such as a kill switch that has not arrived yet. This is the main runtime risk of Remote Config.

Two terms are used below, so here is what they mean in this post:

TermMeaningRemote Config example
App launchThe short window from when the user opens the app until the first screen is ready: process start, Application.onCreate, splash screen.Start the fetch here, so values can be ready before the user reaches a feature.
RuntimeEverything after launch, while the app is open and in use: screens, taps, background work.Code reads a value with getBoolean or getString. A fetch started at runtime may finish at any moment, or not at all.

Launch-time fetch means asking for fresh values during app launch. Runtime risk means the app reads a value while the fetch is still running, or after it failed, and so gets the default or cached value instead of the new one.

App launchApplication.onCreate / splash Runtimeapp is open and in use 1. setDefaultsAsync 2. fetchAndActivate() starts a network call,does not wait for it Screen A reads value Screen B reads value Fetch finishes: now, later, or never Not finished yet: default or cached value Finished: new value from the next read
The fetch begins at launch but ends at runtime. Every read at runtime must be correct whichever value it gets.
// App launch: start the fetch early, and do not block on it
class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        val rc = Firebase.remoteConfig
        rc.setConfigSettingsAsync(remoteConfigSettings { minimumFetchIntervalInSeconds = 3600 })
        rc.setDefaultsAsync(mapOf("new_checkout_enabled" to false))   // safe default: off
        rc.fetchAndActivate()                                         // async, may finish later
    }
}

// Runtime: read with the default as the fallback
fun showCheckout() {
    val useNew = Firebase.remoteConfig.getBoolean("new_checkout_enabled")
    if (useNew) openNewCheckout() else openOldCheckout()   // both paths must work
}

Launching the fetch early, at app start, reduces that risk, because the values usually arrive before the user reaches the screen that needs them. Early fetch does not remove the risk, so combine it with these habits:

App launch Fetch startsasync Arrived in timescreen uses new values Late or faileduse cached or default values fast networkslow / offline
Start the fetch early, and design the screen so it is correct on both paths.

Runtime update: a value changes while the app is open

The code above reads whatever is active. To hear about a change while the app is running, register a real-time listener. It tells you a new template was published; you then activate it and apply it at a safe moment, such as the next screen, not in the middle of a task.

Firebase.remoteConfig.addOnConfigUpdateListener(object : ConfigUpdateListener {
    override fun onUpdate(update: ConfigUpdate) {
        Firebase.remoteConfig.activate().addOnCompleteListener {
            // Apply at a safe moment, e.g. on the next screen, not mid-task
            checkoutFlag = Firebase.remoteConfig.getBoolean("new_checkout_enabled")
        }
    }
    override fun onError(error: FirebaseRemoteConfigException) { /* keep current values */ }
})

See Google’s real-time Remote Config guide for the exact setup and requirements.

4. Conditions and rollouts

A parameter can have several values, each tied to a condition: app version, platform, country, language, a percentage of users, or a user property from Analytics. That gives you staged rollouts (5%, then 50%, then 100%) and per-market settings from one place.

Remote Config also powers A/B Testing: Firebase serves variants to different groups and measures which wins with Analytics.

Rollout timing depends on your users

Publishing in the console does not push a value to every phone at once. Each device gets it at its next successful fetch, and that depends on when the user opens the app and on the minimum fetch interval (12 hours by default). So the same rollout looks different for different apps:

Plan for this: raise the percentage in steps and watch Crashlytics and Analytics between steps. For time-critical changes such as a kill switch, shorten the fetch interval or use real-time Remote Config updates so running apps can pick the change up sooner. Do not rely on it as an instant switch.

5. Common uses

UseExample
Feature flagEnable the new checkout for 10% of users.
Kill switchTurn off a broken feature without a hotfix release.
Force updateCompare min_app_version with the installed version.
Content and copySeasonal banner text or promo colours.
TuningTimeouts, page sizes, retry counts.

6. A tiny example

The shape of the Android code, after you have added the SDK as Google describes:

val rc = Firebase.remoteConfig
rc.setDefaultsAsync(mapOf("promo_banner_enabled" to false))
rc.fetchAndActivate().addOnCompleteListener {
    val show = rc.getBoolean("promo_banner_enabled")
    banner.isVisible = show
}

7. Limits and good habits

Setup steps change often, so follow Google’s own guides rather than a copy here.

← Back to all writing