comparison

Feature Flag vs Remote Config: How to Choose

Feature flag vs remote config: same delivery mechanism, different governance. Runtime behaviour, caching and throttling limits, costs, and when each one breaks.

Published:

Compare the two across 14 dimensions and the argument settles in about five minutes. A feature flag controls whether a code path runs for a given user. Remote config controls what value a variable holds at runtime. Underneath they are the same delivery mechanism: a remotely fetched key-value store your app reads instead of a compiled-in constant. What actually differs is governance (per-user targeting, audit trail, approvals), lifecycle (flags are meant to be deleted, config is meant to persist) and what happens when the fetch fails.

The one-line rule: if the value’s job is to be deleted after a launch, it’s a flag; if it’s a knob you expect to keep turning for years, it’s config.

Vendors blur this on purpose, and their framing follows their product shape. Firebase markets Remote Config under the headline “Personalize and optimize your app with feature flags” (firebase.google.com/products/remote-config). PostHog implements remote config as a JSON payload attached to a feature flag (posthog.com/blog/what-is-a-feature-flag). Neither is wrong. Both are product-shaped definitions sold as category definitions.

Feature flag vs remote config decision rule: delete after launch means flag, tune for years means config

On this page: What a feature flag is · What remote config is · 14 dimensions · Four ways teams get it wrong · Caching and fetch failure · Cost · Decision framework · Firebase walkthrough · Governance · FAQ


What a feature flag actually is

A feature flag is an if statement whose condition reads a remote boolean or variant string instead of a hardcoded one. That single indirection splits two events that used to be welded together: deploying code to a server, and releasing behaviour to users. It is what makes trunk-based development workable. Unfinished code sits in main behind a flag that returns false for everyone.

Three shapes are common. Boolean flags answer on or off. Multivariate flags return one of N variant strings, which is what powers an A/B or A/B/n test. Payload flags return a JSON blob, and that third type is remote config wearing a flag’s clothes.

Four canonical jobs:

  • Progressive rollout. Move a new checkout from 5% of sessions to 25% to everyone over four days, watching error rates between steps. Canary and dark launch are the same move under different names.
  • Kill switch. A payment provider’s SDK starts throwing on iOS 26. Flip one boolean, the broken path stops executing, no hotfix build, no App Store review queue.
  • Entitlement and internal access. Target email contains @yourcompany.com so staff dogfood a feature two weeks early.
  • Operational toggle. Maintenance mode, a circuit breaker that sheds load by disabling an expensive recommendation call, a degraded-mode switch for a flaky third party.

Flags do not measure. A flag tells you the feature is on for a quarter of users. It says nothing about whether those users converted better. That needs an exposure event fired at the evaluation call site, joined to a metric, with random assignment. An experimentation layer, not a toggle.

Lifespan is where the categories split. Release flags are debt with a fuse. Ops flags and permission flags are product surface and should live as long as the feature does. Same mechanism, opposite removal obligations.

What remote config actually is

Remote config is a cloud key-value store the client fetches at startup and periodically after, whose values override in-app defaults compiled into the binary. That last clause is the whole category.

The problem it solves is app-store latency rather than release safety. A typo in paywall copy, a price tier, an ad frequency cap, the ordering of a home-screen carousel, an API base URL that has to move: each of those would otherwise need a binary release, a review queue and an update curve measured in weeks. Config collapses that to a console edit.

The archetypal config values share a tell. None of them has an “off” state. Request timeouts. Retry counts and backoff multipliers. Rate limits. Endpoint URLs. A difficulty curve in a game. A minimum-supported-version string. You keep tuning these; you never delete them.

The in-app defaults contract is the part almost no competing page states plainly. Your binary ships with hardcoded defaults. The fetch overrides them. If the fetch never lands, the defaults are what your user experiences. That is why the failure question has a different answer on each side of the feature flag vs remote config line. A flag SDK usually persists last-known-good state and reconnects; a config default is frozen at build time.

There is a second audience, and it explains why the category exists at all. In mobile and games, config is often owned by product managers or LiveOps teams rather than engineers. The console is the point. The people turning the knobs cannot ship a build and were never meant to.

Feature flag vs remote config across 14 dimensions

14-dimension comparison table of feature flags, remote config and environment variables

DimensionFeature flag platformRemote config (e.g. Firebase RC)Environment variables
Primary jobDecide whether a code path runsDecide what a value isConfigure a deployment
Expected lifespanRelease flags: days to weeks. Ops/entitlement: permanentYears; tuned, not deletedLife of the service
Who typically changes itEngineer, PM, sometimes supportPM / LiveOps via consoleOps, via deploy pipeline
Per-user targetingRules on attributes, segments, cohortsConditions on user properties, audiences, app versionNone. Same value for every user
Percentage rolloutFirst-class, with sticky bucketingFirebase offers a user in random percentile conditionNot possible
Value typesBoolean, variant string, number, JSON payloadString, number, boolean, JSONStrings only (ConfigCat)
Audit trailChange history per flag, who/when/what, on most paid tiersTemplate versioning; no per-flag audit comparable to a flag platformWhatever your CI logs happen to retain
Approval / four-eyesAvailable on enterprise tiers as approval workflowsNot providedCode review on the config repo, if it lives in one
Propagation latencyStreaming or polling SDKs. PostHog states its flag and config changes are not real-time and need a page or app refresh (PostHog)Client fetch on an interval governed by minimumFetchIntervalMillis, subject to server-side throttling (Firebase docs)Requires redeploy or restart
Behaviour on fetch failureLast-known-good cache, local bootstrap, then code defaultCompiled-in in-app defaults applyValue is already in the process
Visibility to end userClient-side flags visible in network traffic; server-side evaluation hides themFetched payload is inspectable unless encryptedFrontend env vars are baked into the bundle and public
Test-matrix impactEach live flag doubles the theoretical state spaceSame, but rarely acknowledgedOne value per environment
Cleanup expectationRelease flags carry a delete dateNo cleanup norm, which is the problemRemoved with the code that read them
Typical pricing meterMAU, seats, or flag requestsFirebase states RC is a no-cost tool (Firebase)Free

Three rows decide it. Lifespan: if the value dies, you want a system that nags you to delete it. Targeting: if one user needs a different answer from another, env vars are out and config conditions may not be expressive enough. Audit: if a regulator, a customer contract or an incident review will ask who changed this value and when, a generic config store will not answer.

Treat every value delivered to a client as public. PostHog documents optional encrypted payloads for exactly this reason. A key called pricing_experiment_control_price is readable by anyone with a proxy, and so is the name of your unreleased feature.

Where they overlap, and the four ways teams get it wrong

Failure 1: config quietly becomes an ungoverned flag system. The tell is a key named new_checkout_enabled holding a boolean, in a config console, changed by three teams over six months, with no owner and no expiry. This is worse than a badly managed flag, because the value looks like configuration. Nobody opens a cleanup ticket for configuration. The dead code behind it survives four releases, then someone flips it back on by accident during an unrelated audit.

Failure 2: a flag used where an experiment was needed. Roll to half your users, open a dashboard, see conversion up 3%, ship. Missing: random assignment, a metric declared before the rollout, a significance test. PostHog names this anti-pattern directly (posthog.com/blog/what-is-a-feature-flag). The mechanical detail worth adding is the exposure event. Unless your SDK fires an event at the moment of evaluation, carrying the user identifier and the variant served, you cannot join flag state to outcomes at all. You are comparing “users in the treatment bucket” against “everyone else”, and everyone else includes users who never reached the screen.

Failure 3: keys multiplying past comprehension. The Firebase Developers walkthrough hits a concrete constraint: user properties used for targeting are finite, and the author warns to archive obsolete ones because “we may run out of user properties quickly if we use one per feature” (medium.com/firebase-developers). Turn that into a budget. Cap live targeting properties, reuse a single feature_cohort property with values instead of one property per feature, review the list quarterly. Same discipline applies to targeting attributes carrying personal data, which you should keep out of client-side rules entirely.

Failure 4: a permanent flag treated as temporary, or the reverse. Someone deletes the kill switch during a cleanup sprint because it had been true for a year. Six weeks later the payment provider breaks and there is no switch. Meanwhile a release flag from 2023 is still branching in production, untested in either direction.

The fix for both is one field. Every flag and every config key gets a type label at creation: release, operational, entitlement, experiment. The label sets the removal obligation.

The reframe worth carrying out of this section is that feature flag vs remote config is rarely the real question. The real question is which of the roughly 40 remotely controlled values in your app are governed, and which are drifting.

Runtime behaviour, caching, throttling, and fetch failure

Runtime lifecycle: in-app defaults, fetch, activate, read, with a failure branch back to defaults

The cycle has four steps, and the third one surprises people: defaults → fetch → activate → read. In Firebase, fetch and activate are separate operations. A value can be fully downloaded and sitting on the device while your code still reads the previous one, because nothing activated it. fetchAndActivate() collapses the two. Most tutorials use it. Most production apps eventually stop, since activating mid-session changes values under a user’s feet.

Two client-side constraints shape everything downstream. Firebase applies server-side fetch throttling, and the SDK enforces a client-side minimum interval via minimumFetchIntervalMillis. A practitioner documented what happens when you fight it: the JS SDK caches its response per browser client, so every user carries a stale copy, and setting minimumFetchIntervalMillis = 0 to defeat that cache runs straight into rate-limit errors (dev.to/jacobandrewsky). Check the current interval defaults and throttle limits in the Firebase docs before you design around either number.

The workaround in that post deserves to be treated as an architecture rather than a hack. Pull the whole template server-side with the Admin SDK (admin.remoteConfig().getTemplate()), hold it in process memory, serve it to clients from your own endpoint, and expose a second, secret-protected endpoint that invalidates the in-memory copy globally. One fetch against Firebase serves every client. Propagation becomes instant on demand.

Read what you just built, though. It is a flag service with a single global cache, no per-user targeting unless you add an evaluation layer, and a new availability dependency: your endpoint. You moved the problem deliberately and took on the maintenance.

Architecture comparison: direct client fetch versus server-side template cache with a secret invalidation route

Now the question people actually search for. If every fetch fails, users get the in-app defaults. Not the last published values. The constants compiled into that specific binary. Your defaults are a kill-switch posture, not boilerplate. Ship true as the default for an unreleased feature and a fetch outage becomes a launch. Ship false for a feature already live everywhere and the outage becomes a rollback on every cold start.

Dedicated flag SDKs answer this differently: local bootstrapping from a payload embedded at render time, last-known-good persistence to disk across launches, streaming connections that reconnect and replay, relay or proxy modes that let one process hold the connection for a fleet. That resilience layer is the substantive engineering difference between the categories, and it is far more real than the marketing distinction.

Observability is the other gap. Teams on Firebase RC have had to build their own change monitoring. eBay published firebase-remote-config-monitor for exactly that: Apache-2.0, 139 stars, 15 open issues, last push 2024-06-21, latest tagged release 2.0 dated 2018-10-29 (github.com/eBay/firebase-remote-config-monitor). Read that as evidence the need is real and the best-known community answer is effectively unmaintained. Not as a recommendation.

What this article has not measured: propagation latency from console publish to value-live-on-device, and real throttle thresholds under load, across Firebase RC, LaunchDarkly, PostHog and Flagsmith. Those numbers need instrumented testing on live accounts. If you need them, measure them. Publish a change carrying a monotonic counter, log the read value with a device timestamp on every app foreground, plot the arrival distribution.

What each costs, using published pricing

The meters do not match, so any single number misleads. Build a model with a visible assumption you can replace.

Assumption: 20 sessions per MAU per month, 5 flag evaluations per session. That is 100 flag requests per MAU per month. Substitute your own; the arithmetic is one multiplication.

ScenarioFlag requests/monthFirebase Remote ConfigPostHog
50k MAU5MNo licence cost4M billable × $0.0001 = $400
500k MAU50MNo licence cost49M × $0.0001 = $4,900
5M MAU500MNo licence cost499M × $0.0001 = $49,900

Rates as published: Firebase states Remote Config is a no-cost tool within the Firebase platform (firebase.google.com/products/remote-config). PostHog publishes 1M feature flag requests free per month and $0.0001 per request thereafter, with remote config payload fetches and experiment evaluations counted against the same flag quota (posthog.com/blog/what-is-a-feature-flag). Re-check both on the vendor pages before you rely on them; PostHog publishes volume discounts this straight-line model ignores.

For LaunchDarkly, Flagsmith, ConfigCat, Statsig and GrowthBook, the number to write down from each pricing page is not the price. It is the meter. Meter mismatch is what makes quotes incomparable: seats, MAU (sometimes with client-side MAU counted separately from server-side), events, or flag requests. An app with 5M MAU and 3 engineers is cheap on a seat meter and brutal on an MAU meter. Invert the app and you invert the answer.

Two costs never appear on any pricing page. First, evaluation latency added to cold start. A blocking config fetch before first paint is a measurable startup regression, which is why the fetch usually runs async against last-known values. Second, the engineering cost of the server-side caching layer above, plus the monitoring you will build because nothing ships it.

Firebase’s product page also carries customer percentages, including Halfbrick +16% revenue, Hotstar +38% engagement, Doodle +42% engagement and FOMO Games +20% LTV. Those are Firebase’s own case-study claims about Firebase, with no methodology, timeframe or control described. Marketing, not evidence.

Decision framework for feature flag vs remote config

Decision flowchart with five yes/no questions routing to flag, config, server-side flag or experiment

Five questions. Does this value ever get deleted? Does it need per-user targeting? Must changes be audited or approved? Must the value stay hidden from the client? Do you need to prove impact?

Mobile-only app, small team, already on Firebase. Remote Config is enough. Add two things before you scale: a naming convention that encodes type, and a calendar entry for a quarterly key audit.

Web plus mobile plus backend, one flag meaning the same thing in three runtimes. Dedicated flag platform with server-side SDKs. Consistent bucketing across runtimes is the hard part. Reimplementing a hash-based assignment identically in Kotlin, TypeScript and Go is how a user ends up in treatment on web and control on iOS.

You need to prove a change worked. Neither, alone. You need random assignment, exposure events joined to a metric, and a significance test. PostHog is explicit that it does not support CUPED variance reduction, mutex or overlapping-experiment groups, or dynamic-attribute cohort targeting (posthog.com/blog/what-is-a-feature-flag), so check those specific capabilities against your analysis plan.

Regulated environment, change approvals required. Audit trail and approval workflow decide it. A four-eyes gate, where the publisher cannot be the author, is a paid-tier flag platform feature. Reconstructing “who turned this on at 02:14” from a console history is not the same thing.

Values must never reach the client. Server-side evaluation only. Nothing fetched by a client is private, encrypted payloads included, because the client must eventually decrypt it.

You want to avoid lock-in. OpenFeature standardises the evaluation API so your call sites survive a vendor change, and its environment-variable provider is a zero-infrastructure start (configcat.com/blog/feature-flags-vs-environment-variables/). The honest limit: it standardises evaluation, not the management UI, not targeting-rule semantics, not audit. Migrating providers still means rebuilding your rules.

Names you will meet while shortlisting. LaunchDarkly, Split, Unleash, Flagsmith, ConfigCat, Statsig, DevCycle and GrowthBook sell flag platforms. AWS AppConfig, Azure App Configuration, HashiCorp Consul and etcd sit on the config side, usually per environment rather than per user. Optimizely, Amplitude Experiment and Eppo sell the experimentation layer.

On build versus buy, practitioner commentary beats vendor copy. In the Hacker News thread on LaunchDarkly’s funding, a commenter argues that homegrown and library-based flagging is normal in SaaS staged rollouts, and that its downside “becomes visible once you have a more focused organization” (news.ycombinator.com/item?id=13265046). The failure mode there is organisational fragmentation rather than technical inadequacy. A third option is live too: flags as reviewed YAML in version control. Flipt’s founder describes serving flag state from declarative non-relational backends including Git, OCI and object storage (news.ycombinator.com/item?id=41460061), and Dorkly is a free open-source flag backend for LaunchDarkly SDKs that uses YAML files in GitHub as the source of truth, built by a former LaunchDarkly employee who discloses that in the post (news.ycombinator.com/item?id=40796697).

Flags as reviewed config in a Git repo collapse the distinction this article opened with. That is the point.

Doing it with Firebase Remote Config, the flag workflow end to end

The sequence for a feature called checkout_v2:

  1. Create a parameter rel_checkout_v2 with in-app default false and console default false.
  2. Add a condition on a custom user property such as is_internal_user == true, serving true. Staff have it; nobody else does.
  3. Add a user in random percentile condition at 5%, serving true. Publish. Watch Crashlytics and your error rate.
  4. Add an app-version condition so only builds at or above the version containing the fix receive true.
  5. Raise the percentile: 5 → 25 → 50 → 100, publishing between steps.

Step 4 is the one people skip, and it is what makes re-enabling safe. Turning a flag off does not fix the binary. Users on the broken build still hold the broken code, and flipping the flag back on hands it to them again. Version-gating re-enables for fixed builds only. The pattern is documented in the Firebase Developers walkthrough.

That walkthrough also names the cleanup obligation that follows from the version gate. The flag persists until effectively nobody is on the bad version, then it goes, and obsolete user properties get archived.

// Android / Kotlin
val remoteConfig = Firebase.remoteConfig
remoteConfig.setDefaultsAsync(mapOf("rel_checkout_v2" to false))
remoteConfig.fetchAndActivate().addOnCompleteListener {
    if (remoteConfig.getBoolean("rel_checkout_v2")) showCheckoutV2() else showCheckoutV1()
}
// Web / JS
const remoteConfig = getRemoteConfig(app)
remoteConfig.defaultConfig = { rel_checkout_v2: false }
await fetchAndActivate(remoteConfig)
const on = getValue(remoteConfig, 'rel_checkout_v2').asBoolean()

Method names differ across SDK major versions, so check both snippets against the current Firebase Remote Config docs.

What this workflow does not give you: no per-flag audit trail comparable to a flag platform’s change history, no approval gate before publish, and no exposure events tied to a metric unless you wire Google Analytics for Firebase yourself.

Governance, naming, ownership, and killing flags before they kill you

Flag lifecycle taxonomy: release, operational, entitlement and experiment flags with owners and removal triggers

Should you remove feature flags? Release and rollout flags, yes. Once the feature is fully rolled out and no meaningful population remains on affected builds, the flag is an untested branch in production. Operational flags, entitlement flags and licence gates, no. They are product surface, and deleting them removes capability.

The test for which is which: ask whether you would ever deliberately set it back to the other value. A kill switch, yes, during an incident. A finished rollout flag, never.

Encode the answer in the key name so it survives the person who created it.

PrefixTypeLifespanRemoval trigger
rel_Release / rolloutDays to weeksFully rolled out for 14 days and <2% of sessions on pre-fix builds
ops_Operational / kill switchPermanentOnly when the feature it guards is deleted
ent_Entitlement / plan gatePermanentOnly when the plan tier is retired
exp_ExperimentLength of the testDecision recorded and winner rolled out

Add a required expiry-date field to every rel_ and exp_ key, plus an owner. Not a team name. A person.

Detection needs no particular vendor. Three mechanisms work anywhere: a code-reference scan in CI that reports keys present in the platform but absent from the codebase and the reverse, a linter rule that fails the build when a rel_ flag passes its declared expiry, and a quarterly walk through every key with the named owner. ConfigCat markets zombie-flag reporting as a product feature, which is useful if you are already there and not a reason to move.

Testing is where laxity bills you. Every simultaneously live flag doubles the theoretical state space, so ten live flags means 1,024 combinations nobody will ever test. The practical policy is narrower. Test the default path and the fully-rolled-out path. Pin flag state explicitly in integration tests instead of letting them read live values. Cap simultaneously live release flags per service at a number the team agrees to; five is a common ceiling.

Config keys need identical treatment and almost never get it. A config key with no owner and no last-changed-by is an unexploded change, one console edit away from an incident nobody can attribute.

Frequently asked questions

Is remote config the same as feature flags?

No, though they share a mechanism. Both are remotely fetched key-value stores read at runtime. Intent and governance differ. A flag decides whether a code path runs and is usually temporary; config decides what a value is and usually persists. Some platforms implement config as a payload on a flag, so the boundary is partly a product decision.

Should you remove feature flags?

Yes for release and rollout flags. Delete them once the feature is live for everyone and no users remain on affected builds, or they become untested branches in production. Keep operational flags such as kill switches and maintenance mode, plus entitlement flags, permanently. Assign a type and an expiry at creation, then fail CI on expired release flags.

What happens if I turn off all feature flags?

Users get whatever the code does when every flag evaluates false or falls back to its default, which is not necessarily “the old app”. Three cases differ. Flags whose off-state is the previous behaviour are safe. Flags whose off-state is an unfinished code path are not. Config values fall back to the compiled in-app default. Your defaults are your outage behaviour.

What is feature flag configuration?

Feature flag configuration is the full definition of a flag rather than its on/off value: the key name, the value type (boolean, variant, JSON payload), the targeting rules and segments, the percentage rollout, the per-environment values, and the default returned when evaluation fails. This lives outside your codebase, which is precisely why an audit trail and named change ownership matter.

What is the purpose of a feature flag?

To separate deploying code from releasing it to users. That enables four jobs: progressive rollout, an instant kill switch with no redeploy, targeted access for internal or beta users, and permanent operational control such as maintenance mode. A flag controls exposure. It does not measure impact.

Can I use Firebase Remote Config as a feature flag service?

Yes, for mobile-first teams, with named caveats. Conditions give you percentage and user-property targeting. Plan for fetch throttling and per-client caching, add app-version conditions so re-enabled features skip broken builds, budget your user properties, and accept that audit trail, approval workflows and stale-flag detection are things you will build. See the walkthrough above.

Why am I getting a Firebase Remote Config internal fetch error?

In rough order of likelihood: fetch throttling from fetching too often or zeroing minimumFetchIntervalMillis; a missing or misconfigured google-services.json or GoogleService-Info.plist, or a bad API key; no network at fetch time; the Remote Config API not enabled on the Google Cloud project; and calling fetch before initialisation completes. Note your SDK version and check the current error semantics in the Firebase docs.

Do I need a feature flag platform if I already have remote config?

Three triggers justify a dedicated platform. One flag must evaluate identically across web, mobile and backend. Changes need an audit trail or approval gate. You need experiment-grade random assignment with significance testing. Absent all three, config plus a naming convention and a quarterly key audit is defensible, and OpenFeature lets you defer the choice without rewriting call sites.


Re-read every Firebase behaviour described here against firebase.google.com/docs/remote-config before acting on it; the two most-linked community write-ups on this topic date from 2019 and 2021. Not measured here: propagation latency from publish to device, and real throttle thresholds under load. Settle feature flag vs remote config in your own stack by labelling every remotely controlled value with a type, an owner and a removal trigger, then watch which list keeps growing.

Frequently Asked Questions

Is remote config the same as feature flags?

No, though they share a mechanism. Both are remotely fetched key-value stores read at runtime. Intent and governance differ. A flag decides whether a code path runs and is usually temporary; config decides what a value is and usually persists. Some platforms implement config as a payload on a flag, so the boundary is partly a product decision.

Should you remove feature flags?

Yes for release and rollout flags. Delete them once the feature is live for everyone and no users remain on affected builds, or they become untested branches in production. Keep operational flags such as kill switches and maintenance mode, plus entitlement flags, permanently. Assign a type and an expiry at creation, then fail CI on expired release flags.

What happens if I turn off all feature flags?

Users get whatever the code does when every flag evaluates false or falls back to its default, which is not necessarily "the old app". Three cases differ. Flags whose off-state is the previous behaviour are safe. Flags whose off-state is an unfinished code path are not. Config values fall back to the compiled in-app default. Your defaults are your outage behaviour.

What is feature flag configuration?

Feature flag configuration is the full definition of a flag rather than its on/off value: the key name, the value type (boolean, variant, JSON payload), the targeting rules and segments, the percentage rollout, the per-environment values, and the default returned when evaluation fails. This lives outside your codebase, which is precisely why an audit trail and named change ownership matter.

What is the purpose of a feature flag?

To separate deploying code from releasing it to users. That enables four jobs: progressive rollout, an instant kill switch with no redeploy, targeted access for internal or beta users, and permanent operational control such as maintenance mode. A flag controls exposure. It does not measure impact.

Can I use Firebase Remote Config as a feature flag service?

Yes, for mobile-first teams, with named caveats. Conditions give you percentage and user-property targeting. Plan for fetch throttling and per-client caching, add app-version conditions so re-enabled features skip broken builds, budget your user properties, and accept that audit trail, approval workflows and stale-flag detection are things you will build. See the [walkthrough](#doing-it-with-firebase-remote-config-the-flag-workflow-end-to-end) above.

Why am I getting a Firebase Remote Config internal fetch error?

In rough order of likelihood: fetch throttling from fetching too often or zeroing `minimumFetchIntervalMillis`; a missing or misconfigured `google-services.json` or `GoogleService-Info.plist`, or a bad API key; no network at fetch time; the Remote Config API not enabled on the Google Cloud project; and calling fetch before initialisation completes. Note your SDK version and check the current error semantics in [the Firebase docs](https://firebase.google.com/docs/remote-config).

Do I need a feature flag platform if I already have remote config?

Three triggers justify a dedicated platform. One flag must evaluate identically across web, mobile and backend. Changes need an audit trail or approval gate. You need experiment-grade random assignment with significance testing. Absent all three, config plus a naming convention and a quarterly key audit is defensible, and OpenFeature lets you defer the choice without rewriting call sites. -- Re-read every Firebase behaviour described here against [firebase.google.com/docs/remote-config](https://firebase.google.com/docs/remote-config) before acting on it; the two most-linked community write-ups on this topic date from 2019 and 2021. Not measured here: propagation latency from publish to device, and real throttle thresholds under load. Settle feature flag vs remote config in your own stack by labelling every remotely controlled value with a type, an owner and a removal trigger, then watch which list keeps growing.*

Explore More

Free Newsletter

Get the Feature Flags Newsletter

Platform benchmarks, real pricing data and progressive delivery practice. No spam.

Free. Unsubscribe any time. See our privacy policy.

Related Articles