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.
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 testnpx 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 --yesAn 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.
Install fireemu as a development dependency:
npm install --save-dev fireemuThe 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.
Start the configured services until interrupted:
npx fireemu upStart the services, run a test command, and stop the services when the command exits:
npx fireemu exec -- npm test
npx fireemu exec -- npx vitest runexec 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 testLimit a run to selected services with --only:
npx fireemu exec --only auth,firestore,storage -- npm testCommon 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.
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.
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.
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
emulatorprofile targets the behavior of the pinned Firebase Emulator Suite release, whilestrictfollows 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 RESTrunQueryresponse omits thedoneflag 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.
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.
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 |
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.
fireemu is licensed under the Apache License 2.0. Third-party notices are listed in THIRD_PARTY_LICENSES.txt.