Skip to content

Repository files navigation

fireemu

An experimental local runtime for testing Firebase SDK and Functions code.

Some Firebase failures are easy to miss locally. A query may need a composite index in production even though it passes against the official emulator. Production limits may reject a request that looked fine during development. Finding those problems only after running against a real Firebase project makes the feedback loop slow and can leave test data behind.

fireemu was built for two jobs:

  • catch selected production-facing problems earlier, including missing Firestore indexes and production limit violations;
  • keep local test runs fast, with no JVM emulator to start and a single command that starts the services, runs the test command, and shuts everything down.

fireemu is experimental. It is not a replacement for the official Firebase Emulator Suite or for testing against a real Firebase project. Use it as an additional test target, keep the official emulator in your test matrix, and verify important flows against production before shipping.

Quick start

Node.js 20 or newer is required. For Functions, an explicit functions.runner command wins and FIREEMU_NODE is an exact executable override. On Unix, automatic selection probes the first Node executable on PATH plus installed runtimes under VOLTA_HOME before loading user code. This limits automatic execution to normal command resolution and explicitly configured version-manager storage. For a Node 20 or newer request, candidates that can synchronously load an ES module from CommonJS are ranked first; the firebase.json runtime major, package.json engines.node, and stable discovery order then break ties. A loader-capable local fallback may therefore use a different major when the requested candidate lacks that loading capability, and the mismatch is reported. A malformed engine constraint still fails before loading. The runner never evaluates user code under one automatic candidate and retries it under another. On Windows, FIREEMU_NODE is used directly when set and otherwise the first node on PATH is used, matching the previous runner behavior; use functions.runner when an exact Windows runtime is required.

The runtime uses at most four async worker threads and 64 blocking worker threads by default. FIREEMU_WORKER_THREADS (1 through 64) and FIREEMU_MAX_BLOCKING_THREADS (1 through 512) provide explicit overrides for unusually large test workloads.

npm install --save-dev fireemu
npx fireemu init
npx fireemu doctor
npx fireemu exec -- npm test

npx fireemu init creates fireemu.json in the current directory. In a terminal, a short wizard asks which compatibility profile to use and whether to reuse an existing firebase.json.

The strict profile, the default and the one init recommends, behaves like production Firebase where the official emulator does not: composite indexes are checked with production's rules, production query limits are enforced, and ID tokens are verified. Choose the emulator profile when matching the pinned official emulator is more important.

If firebase.json exists, init references it instead of copying its settings. Rules, indexes, Functions codebases, and emulator ports are loaded from that file each time fireemu starts. firebase-tools@15.28.2 does not impose a Functions codebase-count limit, but fireemu applies a documented local safety budget of 32 simultaneously selected codebases because each starts a Node runner; --only functions:<codebase> selects one from a larger project.

Functions source reloads hash all non-ignored file content. One daemon-wide source-work admission paces scans and snapshots to 64 MiB/s and 20,000 directory entries/s, stops abandoned work between 64 KiB chunks, and rejects a watch or reload operation whose source tree exceeds 100,000 entries or 128 directory levels. These are local resource-safety limits rather than Firebase CLI compatibility claims.

Second-generation callable functions support the Firebase Web SDK's .stream() API. response.sendChunk() and onCallGenkit stream values are forwarded progressively, the final result resolves when the handler completes, and client cancellation reaches the handler's response signal. Streamed responses use bounded backpressure and the production 10 MiB uncompressed response limit. A local runner response with a non-identity Content-Encoding is refused rather than allowing compressed bytes to bypass that limit.

For CI or scripted setup, use the non-interactive form:

npx fireemu init --yes

An existing fireemu.json is left untouched unless --force is supplied. Other useful options are --profile strict|emulator, --firebase-json <path>, --interactive, and --no-interactive.

The generated configuration uses Standard edition Firestore with the Native API:

{
  "$schema": "https://fireemu.dev/spec/config/fireemu.schema.json",
  "schemaVersion": 1,
  "profile": "strict",
  "firestore": {
    "edition": "standard",
    "apiMode": "native"
  }
}

See the configuration schema for the complete set of options.

--config accepts either a canonical fireemu configuration (with "schemaVersion": 1) or a Firebase project configuration. A file without schemaVersion is refused if it contains fireemu-only keys such as profile, daemon, or auth.totp, with a diagnostic naming the file, key, and required version. This check also applies to --firebase-json and files referenced by firebaseJson; keep fireemu settings in the canonical file and pass it with --config. Shared Firebase product sections and deployment settings remain supported, and filenames do not determine the format.

Installation

Install fireemu as a development dependency:

npm install --save-dev fireemu

The npm package installs the binary for the current platform as an optional dependency. There is no install script, and no component is downloaded after npm finishes resolving the package.

Platform Architecture
macOS 13 or newer Apple silicon, Intel
Linux x86-64, arm64
Windows 10 or newer x86-64

Linux packages are statically linked. Java is not required. Running a Functions codebase requires Node.js and firebase-functions v6 or v7 in that codebase.

Releases are Git tags. Each tag is built by the release workflow, which publishes the launcher and the platform packages to npm with provenance; the platform package tarballs on npm are the release archives. The changes in each release are listed in CHANGELOG.md.

Usage

Start the configured services until interrupted:

npx fireemu up

Start the services, run a test command, and stop the services when the command exits:

npx fireemu exec -- npm test
npx fireemu exec -- npx vitest run

exec returns the child command's exit status and forwards SIGINT and SIGTERM. It also exports the emulator host variables used by Firebase SDKs. Like the official command, it starts without the Emulator UI unless --ui is present. The fireemu-specific --ui-port <port> remains an explicit UI override, and port 0 disables it.

The official CLI spellings are available as aliases:

npx fireemu emulators:start
npx fireemu emulators:exec -- npm test

Limit a run to selected services with --only:

npx fireemu exec --only auth,firestore,storage -- npm test

Common commands:

Command Purpose
fireemu init Create fireemu.json through a short wizard or non-interactively
fireemu up Start the configured services
fireemu exec -- <command> Start the services, run one command, then stop
fireemu emulators:export <dir> Export data from a running suite
fireemu doctor Check the installed binary, Node.js, UI, and Functions runner
fireemu capabilities Print the current capability manifest

On Windows, emulators:export and --export-on-exit currently fail before writing any path. Import and the rest of the emulator runtime remain available. Atomic export publication will be enabled when the Windows implementation can provide the same identity-bound replacement and cleanup guarantees as the Unix implementation.

On Unix, export publication also refuses a destination below any namespace ancestor that is owned by another user, writable by the group or other users, or, on macOS, carries an extended ACL. Choose a dedicated directory below a private namespace rather than /tmp or a shared project directory. This restriction ensures that cleanup can remove only the private stage identity created by the current process.

Supported features

The following is a product-level summary, not a claim that every API and edge case is implemented.

Product Current scope
Cloud Firestore Native-mode gRPC, REST, and WebChannel access; transactions, queries, listeners, indexes, limits, and Security Rules
Firebase Authentication Client and Admin REST surfaces, emulator actions, custom tokens, email and phone flows, MFA, tenants, and fixture identity providers
Cloud Storage for Firebase Firebase and JSON object APIs, resumable uploads, generations, listing, and Security Rules
Cloud Functions for Firebase v2 HTTP and callable functions, including callable streaming, plus Firestore, Storage, and scheduled functions through the bundled Node.js runner
Cloud Pub/Sub The documented gRPC subset used by the supported Functions flows
Emulator logging The EmulatorLog WebSocket with bounded local history and per-function Node log attribution
Firebase App Check A fireemu-specific local implementation; this is not an official Emulator Suite parity claim
Emulator UI A fireemu UI for supported data and controls, with scoped workflow and official Logs interoperability evidence

Run fireemu capabilities or inspect the Capability Manifest before depending on a specific API. Each capability records whether it is implemented, partial, validation-only, or unsupported.

Gap from production Firebase

fireemu aims to catch selected failures before a production run, but it does not reproduce the Firebase backend.

  • Strict mode checks known Firestore index and request-limit cases, but it cannot guarantee that every request accepted locally will be accepted by production.
  • Real quota accounting, billing, IAM, organization policy, regional behavior, network conditions, and service rollouts are outside the local runtime.
  • Security Rules and SDK behavior are implemented against documented and measured behavior, but the hosted services remain the source of truth.
  • Performance results from a loopback process do not predict production latency or throughput.

These are the gaps currently known and documented by the project, not an exhaustive list. Firebase changes independently, and unrecorded differences may exist. Test important workflows against a real Firebase project before release.

Gap from the official Firebase Emulator Suite

fireemu is compatible with the listed Local Emulator Suite products as shipped by firebase-tools 15.28.2 -- Cloud Firestore, Firebase Authentication, Cloud Storage for Firebase, Cloud Functions, Cloud Pub/Sub and Eventarc, with Security Rules on the Firestore and Storage surfaces -- under the emulator compatibility profile and the evidence recorded in spec/compatibility/contract.json; it makes no complete-suite and no unqualified superset claim while Realtime Database, Firebase Hosting, App Hosting and Data Connect are deferred and Firebase Extensions is not planned.

In practical terms:

  • the emulator profile targets the behavior of the pinned Firebase Emulator Suite release, while strict follows production Firebase and refuses what production refuses;
  • where production and the official emulator disagree, fireemu follows production and records the difference in conformance/divergences.json. Two examples: an equality filter combined with an inequality on another field is refused without a composite index, as production does, and a REST runQuery response omits the done flag that the official emulator adds;
  • fireemu serves its own UI with the supported Auth, Firestore, Storage, Functions, Rules diagnostics and Firebase alerts workflows. The official UI Logs browser boundary is also tested; Android, Apple and Unity SDK matrices plus optional accessibility and visual snapshots remain outside the current scope;
  • Eventarc publication and trigger-management workflows, Cloud Tasks queue inspection, Pub/Sub snapshots, and loopback push delivery are supported through the Functions and Pub/Sub runtimes. Local safety limits and reload semantics are recorded in the compatibility contract;
  • Realtime Database, Firebase Hosting, App Hosting, and Data Connect are deferred and not served;
  • Firebase Extensions is not planned.

This list reflects differences known to the project at the current compatibility baseline. It may be incomplete. The Compatibility Contract is the authoritative machine-readable scope, and the compatibility contract guide explains how claims are tied to tests and conformance evidence.

Why use both profiles?

The two profiles answer different questions:

Profile Question it helps answer
strict Would production Firebase accept what this test does?
emulator Does this behavior match the pinned official emulator closely enough for the declared capability?

npx fireemu init recommends strict. Use both profiles in CI when both questions matter.

Performance

fireemu is measured against the official Firestore emulator by a paired benchmark (benchmark.yml, harness in tools/bench/). Both emulators run sequentially on the same GitHub Actions Linux runner, under the emulator profile, driven by the same SDK workloads with result validation. The figures below are from one standard run (5 measured pairs, commit f3b942c) and are paired ratios with 95% confidence intervals; absolute values depend on the runner.

Area Official fireemu Ratio
Startup until the SDK can use Firestore 3,043 ms 140 ms 21.6x faster [21.4, 21.8]
Idle memory, empty database (PSS) 390 MiB 11 MiB 34x smaller
Peak memory over a trial (cgroup) 849 MiB 79 MiB 10.7x smaller [10.2, 11.1]
Firestore throughput, 22 workloads -- -- 1.1x to 5.2x higher

Project status

fireemu is under active development and has not reached a stable compatibility promise. Configuration, unsupported behavior, and edge-case semantics may change between releases.

Bug reports that include the Firebase product, SDK version, fireemu profile, and a minimal reproduction are especially useful. When reporting a compatibility problem, note whether the reference behavior came from production Firebase or the official emulator; they do not always behave the same way.

Contributor build and test commands are documented in the development guide.

License

fireemu is licensed under the Apache License 2.0. Third-party notices are listed in THIRD_PARTY_LICENSES.txt.

About

An experimental local runtime for testing Firebase.

Resources

Stars

8 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages