Imagine being able to change your app's text, colors, feature flags, or pricing — instantly, for all users — without pushing a single app update. That's exactly what Firebase Remote Config enables. It's one of the most powerful and underused tools in the Firebase suite for Android developers.
In this guide you'll implement Firebase Remote Config in an Android app using Kotlin, from initial setup to fetching values with coroutines, setting default values, and using it for A/B testing and feature flags.
What is Firebase Remote Config?
Firebase Remote Config is a cloud-based service that lets you define key-value parameters in the Firebase Console and fetch them in your app at runtime. Your app can then use these values to change its behavior and appearance — without requiring users to update the app.
Key features of Firebase Remote Config:
- Parameter Configuration: Define string, number, boolean, or JSON parameters in the Firebase Console and change them anytime
- Conditional Delivery: Target specific users by app version, platform, country, or custom audience
- A/B Testing: Test different parameter values on different user segments to find the best configuration
- Default Values: App always falls back to local defaults if fetch fails — no crashes, no broken UI
- Real-time Updates: Changes propagate to all users within minutes, no Play Store review required
Implementing Firebase Remote Config — Step by Step
Step 1: Add Firebase to your project
Use the Firebase BoM (Bill of Materials) to manage all Firebase library versions in one place. Add to your build.gradle (app):
dependencies {
// Firebase BoM — manages all Firebase versions automatically
implementation platform('com.google.firebase:firebase-bom:33.1.0')
// Remote Config (version managed by BoM)
implementation 'com.google.firebase:firebase-config-ktx'
// Analytics (required by Remote Config)
implementation 'com.google.firebase:firebase-analytics-ktx'
}
Make sure you have the Google Services plugin applied at the top of your build.gradle (app):
plugins {
id 'com.android.application'
id 'com.google.gms.google-services' // Required for Firebase
}
Step 2: Create default values XML
This is a critical step that many tutorials skip. Default values ensure your app works correctly even before it fetches from the server — on first launch, offline, or when fetch fails. Create res/xml/remote_config_defaults.xml:
<?xml version="1.0" encoding="utf-8"?>
<defaultsMap>
<entry>
<key>welcome_message</key>
<value>Welcome to Android Academics!</value>
</entry>
<entry>
<key>is_feature_enabled</key>
<value>false</value>
</entry>
<entry>
<key>max_items_to_show</key>
<value>10</value>
</entry>
</defaultsMap>
Step 3: Initialize Firebase Remote Config
Initialize Remote Config in your Application class. The minimumFetchIntervalInSeconds controls how often your app fetches from the server. Set it to 0 during development for instant updates, and 3600 (1 hour) in production.
import android.app.Application
import com.google.firebase.remoteconfig.FirebaseRemoteConfig
import com.google.firebase.remoteconfig.ktx.remoteConfig
import com.google.firebase.remoteconfig.ktx.remoteConfigSettings
import com.google.firebase.ktx.Firebase
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
initRemoteConfig()
}
private fun initRemoteConfig() {
val remoteConfig = Firebase.remoteConfig
val configSettings = remoteConfigSettings {
// Use 0 for development, 3600 for production
minimumFetchIntervalInSeconds = if (BuildConfig.DEBUG) 0 else 3600
}
remoteConfig.setConfigSettingsAsync(configSettings)
// Set default values from XML
remoteConfig.setDefaultsAsync(R.xml.remote_config_defaults)
}
}
Register your Application class in AndroidManifest.xml:
<application
android:name=".MyApp"
... >
</application>
Step 4: Define parameters in Firebase Console
Go to Firebase Console → Remote Config → Add parameter. Add the same keys you defined in your defaults XML:
welcome_message→ "Welcome back, Explorer!" (or any string)is_feature_enabled→trueorfalsemax_items_to_show→ any number
Click Publish changes — your parameters are now live in the cloud.
Step 5: Fetch and activate values
Fetch the latest values from the server and activate them. Use fetchAndActivate() which fetches and applies in one call. Here's both the coroutine-based (recommended) and callback-based approaches:
Using Coroutines (recommended):
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.google.firebase.ktx.Firebase
import com.google.firebase.remoteconfig.ktx.remoteConfig
import kotlinx.coroutines.launch
import kotlinx.coroutines.tasks.await
class MainViewModel : ViewModel() {
private val remoteConfig = Firebase.remoteConfig
fun fetchRemoteConfig(onComplete: (Boolean) -> Unit) {
viewModelScope.launch {
try {
val updated = remoteConfig.fetchAndActivate().await()
onComplete(updated)
} catch (e: Exception) {
// Fallback to cached/default values automatically
onComplete(false)
}
}
}
// Read values — always returns a value (remote, cached, or default)
fun getWelcomeMessage(): String =
remoteConfig.getString("welcome_message")
fun isFeatureEnabled(): Boolean =
remoteConfig.getBoolean("is_feature_enabled")
fun getMaxItems(): Int =
remoteConfig.getLong("max_items_to_show").toInt()
}
Using Callbacks (alternative):
private fun fetchRemoteConfig() {
Firebase.remoteConfig.fetchAndActivate()
.addOnCompleteListener { task ->
if (task.isSuccessful) {
val welcomeMessage = Firebase.remoteConfig.getString("welcome_message")
binding.tvMessage.text = welcomeMessage
} else {
// App uses cached or default values automatically
binding.tvMessage.text = Firebase.remoteConfig.getString("welcome_message")
}
}
}
Step 6: Use the values in your Activity/Fragment
class MainActivity : AppCompatActivity() {
private val viewModel: MainViewModel by viewModels()
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
// Show defaults immediately while fetching
updateUI()
// Fetch latest config from server
viewModel.fetchRemoteConfig { updated ->
if (updated) updateUI() // Refresh UI with new values
}
}
private fun updateUI() {
binding.tvMessage.text = viewModel.getWelcomeMessage()
binding.btnNewFeature.isVisible = viewModel.isFeatureEnabled()
}
}
Common Use Cases for Remote Config
- Feature flags: Enable or disable features for all users or a subset — great for gradual rollouts
- A/B testing: Show different UI or copy to different user groups and measure which performs better
- Promotional banners: Toggle sale banners or promotional messages without an update
- API endpoints: Switch between staging and production URLs dynamically
- App theming: Change colors, fonts, or layout configurations remotely
Best Practices
- Always set default values — never rely solely on remote values. Your app must work offline and on first launch with sensible defaults.
- Use BuildConfig.DEBUG for fetch interval — set
minimumFetchIntervalInSeconds = 0in debug builds so you can test changes instantly. Use3600in production to avoid hitting rate limits. - Fetch on app start, not on every screen — fetch once when the app launches and cache the result. Don't fetch on every Activity or Fragment.
- Use coroutines over callbacks —
fetchAndActivate().await()inside a ViewModel is cleaner and integrates with your existing Kotlin Coroutines architecture. - Don't store sensitive data — Remote Config values are not encrypted and can be inspected. Never store API keys, secrets, or passwords in Remote Config.
Frequently Asked Questions
How often does Firebase Remote Config fetch new values?
In production, Remote Config has a default minimum fetch interval of 12 hours. You can lower it (e.g. 3600 for 1 hour) in your config settings but fetching too frequently may hit rate limits. Set minimumFetchIntervalInSeconds = 0 during development for instant updates.
What happens if Remote Config fetch fails?
If fetch fails, the app automatically uses the last successfully fetched and cached values. If no cached values exist, it falls back to the default values you defined locally in remote_config_defaults.xml. This ensures your app always works correctly.
Can I use Remote Config for A/B testing?
Yes — Firebase Remote Config integrates directly with Firebase A/B Testing. You can create experiments in the Firebase Console to show different parameter values to different user groups and measure impact using Firebase Analytics.
Is Firebase Remote Config free?
Yes — Remote Config is free on all Firebase pricing plans including the free Spark plan, with no limits on active users or parameter fetches.
- Use Firebase BoM to manage Firebase dependency versions
- Always define default values in
remote_config_defaults.xml - Set minimumFetchIntervalInSeconds = 0 in debug, 3600 in production
- Use coroutines + fetchAndActivate().await() for clean async fetching
- Never store sensitive data like API keys in Remote Config
- Use for feature flags, A/B testing, and dynamic content without app updates