Skip to content

Configuration files

Fireemu reads two kinds of files:

  • fireemu.toml holds Fireemu’s own settings, such as the profile, Authentication project configuration and the clock. It contains schemaVersion = 1. The same settings can be written as JSON in fireemu.json; a directory that has both is refused (see Which files are loaded). See the configuration schema.
  • firebase.json is the file the Firebase CLI uses. Fireemu reads ports, Security Rules, indexes and Functions codebases from it, every time it starts.

Keep Fireemu-specific settings in fireemu.toml rather than in firebase.json. To use both, name the firebase.json in fireemu.toml:

#:schema https://raw.githubusercontent.com/fireemu/fireemu/main/spec/config/fireemu.schema.json
# Configuration schema version: 1.
schemaVersion = 1
# Compatibility profile: "strict" or "emulator".
profile = "strict"
# Path to Firebase project configuration, relative to this file; a non-empty string.
firebaseJson = "firebase.json"

npx fireemu init --firebase-json firebase.json writes this for you.

up, exec, emulators:start and emulators:exec choose their configuration files as follows.

  1. --config <file> and --firebase-json <file> load exactly the files they name, and nothing is searched for. --config parses a .toml path as TOML (case-insensitive, including .TOML) and every other extension as JSON. A TOML configuration must set schemaVersion = 1; it is never read as a firebase.json, which is JSON only. --firebase-json always reads JSON.
  2. Otherwise, the single fireemu.toml or fireemu.json in the current directory is loaded as if it were passed with --config. If both files exist, startup is refused: remove one or select a file with --config. Its firebaseJson entry, resolved relative to the loaded file, names the firebase.json to load. A firebase.json beside a fireemu.toml without a firebaseJson entry is not loaded, and the startup output says so. Neither fireemu.toml nor fireemu.json in a parent directory is used, because the paths it contains are relative to the current directory. Relative paths inside a canonical file (rules.source, storage.rules, functions.source, firestore.indexFile and the other file settings) are read from the working directory, whichever directory the file is in; only firebaseJson and the paths inside a firebase.json are read from the file’s own directory.
  3. Otherwise, the nearest firebase.json is loaded as if it were passed with --firebase-json: the one in the current directory, else the first one found in a parent directory, as the Firebase CLI finds it. Its paths and the .firebaserc beside it are read from its directory.
  4. Otherwise, the built-in defaults apply, and no Security Rules are loaded.

--no-config-discovery skips steps 2 and 3. The config: line of the startup output names the files that were loaded.

If you relied on the old behavior, where a firebase.json next to your tests was ignored, pass --no-config-discovery. Discovery means that the project ID comes from the .firebaserc beside the discovered firebase.json, that its emulator ports, Hub, UI and single-project settings apply, and that a functions entry starts the Functions runtime. fireemu capabilities also reports the profile of a discovered fireemu.toml.

A discovered file can name Functions code to run and the rules to enforce, so on Unix the search checks who owns what it finds, as git checks repository ownership. The Firebase CLI does not check this. The trusted owners are you, root, and, when you run as root through sudo, the user in SUDO_UID.

  • A fireemu.toml, fireemu.json or firebase.json whose owner is not trusted, or that any user can write, is skipped with a warning. Group write is allowed, so files created under a user-private-group umask (002, the Debian and Ubuntu default) are loaded.
  • A .firebaserc names only project and target aliases, never code or rules, so its owner is not checked. It is skipped only when it, or its directory, can be written by any user.
  • The search stops before a parent directory whose owner is not trusted or that any user can write, such as /tmp. It also stops, without a warning, at a parent it cannot inspect, such as one you may not enter.
  • The owner of the current directory is not checked, because you chose to run there. A current directory that any user can write is not searched at all.
  • A symbolic link is judged by the file it points to. The directory that holds the target is not checked.
  • Each candidate is opened once. Its owner and mode are checked on the open file before anything is read, and its text is then read from the same file. A discovered file larger than 16 MiB is refused with an error.

A skipped file or directory is named in a warning, and the run continues as if nothing had been found. To load a skipped file anyway, name it with --config or --firebase-json. To silence the warning, pass --no-config-discovery. Errors in a discovered file say that the search found the file. On Windows, ownership is not checked.

Two common setups run into this rule:

  • A root container with a bind-mounted checkout, such as a GitHub Actions container: job, or docker run -v "$PWD":/app as root. The files are owned by a host user the container’s root does not trust. Use the explicit flags, or chown the checkout. The .firebaserc still names the project. Rootless Podman maps your user to the container’s root, so it is not affected.
  • sudo. Files owned by the user in SUDO_UID are trusted.

fireemu.toml is validated at startup, and a value Fireemu does not accept stops it with an error. A key the schema does not list and a value of the wrong type are refused in both formats by up, exec and config show, naming the file, the key and the type it should have had, for example fireemu.toml: daemon.firestorePort must be an integer, found a string. Integer settings refuse floats even when their value is integral: write 8080 rather than 8080.0, as the error message suggests. The configuration schema is a JSON Schema you can also use in your editor.

fireemu capabilities prints the capability manifest for the profile your configuration resolves to.

fireemu init --reference also writes fireemu.reference.toml, a commented reference generated from the schema. With an existing fireemu.json, it writes fireemu.reference.jsonc instead, so the reference keys match your configuration format. Fireemu never loads this file.

  • The normal fireemu.toml stays minimal. Copying a reference key into it makes that key explicit, which stops productionExact from switching it.
  • These keys stay commented out in the reference: keys without defaults, keys whose presence selects behavior, keys governed by productionExact, and keys accepted for forward compatibility that currently have no effect (marked as such in their comment).
  • Combine --reference with --profile or --firebase-json when initializing. With an existing fireemu.toml or fireemu.json and neither of those options, only the reference is written.
  • Existing output files require --force to replace.

Generated schema annotations refer to the schema hosted in the GitHub repository. Older configurations containing https://fireemu.dev/spec/config/fireemu.schema.json still load, but replace that annotation with https://raw.githubusercontent.com/fireemu/fireemu/main/spec/config/fireemu.schema.json for editor validation. Fireemu validates against its bundled schema and does not fetch the annotation URL.

TOML files use the same JSON Schema, validation and defaults as JSON files. Start a file with #:schema https://raw.githubusercontent.com/fireemu/fireemu/main/spec/config/fireemu.schema.json to select the schema in Taplo or Even Better TOML. Quote timestamp values: TOML datetimes are refused with the key name because the schema has no datetime type.

TOML has no null. For every nullable setting below, omit the key in its containing table; for nullable array items, omit the item. Keep the containing table or array when its presence is intentional. Empty arrays and empty tables retain their existing meaning.

Nullable JSON keys Meaning of null and TOML omission
limits.queryCatalog, firestore.textSearch.visibilityLag Accepted with no runtime effect. Omission also removes the explicit value and startup note for these keys.
limits.firestorePlan.compositeIndexLimitOverride, limits.firestorePlan.singleFieldConfigLimitOverride, limits.firestorePlan.enterpriseIndexLimitOverride No override; non-null overrides are currently refused.
auth.providers, auth.providers.oidc, auth.providers.saml No provider seed declaration. An empty array explicitly declares an empty replacement and is different from omission.
auth.providers.oidc[].displayName, auth.providers.oidc[].clientSecret, auth.providers.saml[].displayName No optional provider value.
auth.authorizedDomains No seed; preserve the default domains. An empty array declares no domains.
auth.authorizedDomains[] Ignore this item; leave it out of the TOML array.
auth.mfa, auth.multiTenant, auth.tenants No declaration; keep the applicable defaults.
auth.mfa.enabledProviders, auth.mfa.providerConfigs No providers of this kind in the declared MFA configuration. Keep the auth.mfa table if declaring MFA.
auth.mfa.providerConfigs[].totpProviderConfig Ignore this provider entry; omit the key in that entry.
auth.mfa.providerConfigs[].totpProviderConfig.adjacentIntervals Use zero adjacent intervals in the declared TOTP provider; keep its table.
auth.blockingFunctions.triggers.beforeCreate, auth.blockingFunctions.triggers.beforeSignIn Disable this trigger in an explicit trigger selection. Keep [auth.blockingFunctions.triggers]; omitting that entire table enables discovery instead.
auth.quota.signUpQuotaConfig Clear the temporary quota override, including an imported override. Keep [auth.quota] empty; omitting the entire quota table preserves an imported override.
auth.passwordPolicy.constraints.maxLength, auth.passwordPolicyOverrides[].passwordPolicy.constraints.maxLength No custom maximum length.