Skip to main content
Glama
Firenook

Firenook

Official
README.md
<p align="center">
  <picture>
    <source media="(prefers-color-scheme: dark)" srcset="brand/logo/firenook-logo-on-dark.svg">
    <img alt="Firenook" src="brand/logo/firenook-logo.svg" height="72">
  </picture>
</p>

<h3 align="center">A faster drop-in replacement for the Firebase Local Emulator Suite</h3>

<p align="center">
  Keep your <code>firebase.json</code>, SDKs and ports. Get 40× faster writes,
  10× less memory, no Java, and data that survives restarts.
</p>

<p align="center">
  <a href="https://www.npmjs.com/package/firenook"><img alt="npm" src="https://img.shields.io/npm/v/firenook?label=npm&color=1c53cf"></a>
  <a href="LICENSE"><img alt="License: Apache-2.0" src="https://img.shields.io/badge/license-Apache--2.0-1c53cf"></a>
  <img alt="macOS, Linux and Windows" src="https://img.shields.io/badge/platforms-macOS%20%C2%B7%20Linux%20%C2%B7%20Windows-555">
</p>

<p align="center">
  <a href="docs/getting-started.md">Getting started</a> ·
  <a href="docs/README.md">Docs</a> ·
  <a href="docs/benchmarks.md">Benchmarks</a> ·
  <a href="COMPATIBILITY.md">Compatibility</a> ·
  <a href="https://github.com/firenook-dev/firenook/releases">Releases</a>
</p>

<p align="center">
  <img alt="npx firebase emulators:start becomes npx firenook emulators:start --keep-data: the start-up card picks up 1.2 million kept documents, then the ready summary and a live log of function calls, including a failed webhook with its stack trace" src="docs/assets/terminal.gif" width="760">
</p>

**Already using the Firebase emulators?** Install Firenook and change one word:

```sh
npm install --save-dev firenook
```

```diff
- firebase emulators:start --import ./data
+ firenook emulators:start --import ./data
```

Same flags, same ports, and your `firebase.json`, rules, Functions code and app
stay as they are. In a terminal, run it as `npx firenook emulators:start`. To
keep your data between runs, with no export at every stop, add `--keep-data`.

Firenook needs Node 22, 24 or 26, on macOS, Linux or Windows. Starting a new project?
`npx firenook init` sets one up. [Get started](#get-started) covers both.

## Why Firenook

**A drop-in for the official emulator.** Firenook reads `firebase.json`,
`.firebaserc`, rules and indexes the way the Firebase CLI does, serves
Firestore, Auth, Storage, Functions, Pub/Sub, Cloud Tasks and Eventarc on the
same ports, and your client and Admin SDKs connect unchanged. It imports and
exports the official format, so your data moves both ways. Every change is
checked against recorded behaviour of the official emulator.

**Fast and light.** The services are native Rust and the data lives on disk,
not in a Java heap. On a real application's two-hour workload, Firenook
peaked at 2.11 GiB of memory where the official emulator reached 22.57 GiB,
answered writes in 5.1 ms against 208 ms at the median, and used 61% less CPU.

**Your data stays.** Add `--keep-data` and Firestore, Auth and Storage come
back with all your data in about half a second, even with millions of
documents: no export at every stop, no import at every start. A
crash loses at most the last second of writes, where the official emulator
loses everything since its last export, and a stop always closes the data
cleanly.

**One package, nothing else to install.** No Java, no firebase-tools, nothing
else downloaded at install or start: one npm package with a native engine for
macOS, Linux and Windows. Node runs your Functions, as in production. (An
Extension from the registry is fetched once, on first use;
`firenook ext:vendor` makes even that offline.)

**A console and a terminal made for it.** A web console for every service,
live as your app runs, and a terminal screen that shows each function call,
what triggered it, how long it took, and the stack trace when it fails.

**Ready for your agent.** `firenook mcp` gives a coding agent the running
suite: read and write Firestore, manage users and sign in as them, read the
logs and each function call with its error, ask the Security Rules why a
request is denied, and work with Storage files, Pub/Sub, Cloud Tasks and
Eventarc. `npx firenook mcp add` sets it up for Claude Code, Cursor and VS Code
in the project's own files; [other agents](docs/mcp.md#connect-your-agent) run
the same `npx firenook mcp`. Nothing leaves your machine.

## What it emulates

| Service | Port | Highlights |
| --- | ---: | --- |
| Firestore | 8080 | Native and web SDKs, realtime listeners, Security Rules, named databases, official import and export |
| Authentication | 9099 | Every operation of the official Auth emulator: password, email link, phone, anonymous, custom tokens, test sign-in with Google, Apple and other providers, MFA, passkeys, tenants, blocking functions |
| Cloud Storage | 9199 | Firebase and Cloud Storage APIs, Security Rules evaluated natively, including `firestore.get()` and `exists()` |
| Cloud Functions | 5001 | HTTP, callable and streaming functions; Firestore, Storage, Auth, Pub/Sub, Eventarc, schedule and task-queue triggers; reload on save; `--inspect-functions`; `functions:invoke` for any trigger |
| Extensions | 5001 | Local, vendored or registry sources, offline once vendored |
| Pub/Sub | 8085 | Every RPC over gRPC and HTTP/JSON: push, ordering, filters, dead-letter topics, seek, snapshots, Avro schemas |
| Cloud Tasks | 9499 | Queues for `onTaskDispatched` with the official retry and rate-limit behaviour |
| Eventarc | 9299 | Custom events delivered to `onCustomEventPublished` |

The console is on 4000, the hub on 4400 and logging on 4500. These are the
official suite's ports, and `firebase.json` changes them the same way.

Realtime Database, Hosting, App Hosting and Data Connect are not emulated; a
`firebase.json` that configures them still starts, with a warning.
[COMPATIBILITY.md](COMPATIBILITY.md) records what each service covers and what
it does not.

## The console

**The console the Firebase emulators should have had.** Google's Emulator UI
has no page for your Functions, Pub/Sub, Cloud Tasks or Eventarc, only a log.
Firenook's console covers every service it runs, live, on the Emulator UI's
port, at <http://127.0.0.1:4000/console>:

- **Functions:** every call with what triggered it, its outcome, its duration
  and its logs, and every schedule. The official UI has only the log.
- **Authentication:** users, their activity, and an inbox of the sign-in codes
  and email links Auth would have sent, so you never dig through the terminal
  for them.
- **Firestore and Storage:** browse, edit and upload, and read their
  security rules.
- **Pub/Sub, Cloud Tasks and Eventarc,** which the official UI has no pages
  for.
- **An Overview** of every service's health and recent problems, with
  snapshots and resets a click away.

Light and dark, works offline, sends nothing anywhere. Bookmarks to the
official UI's pages open the matching console page.

<picture>
  <source media="(prefers-color-scheme: dark)" srcset="docs/assets/console-overview-dark.png">
  <img alt="The console's Overview: the health of all nine services with their counts and ports, and recent problems" src="docs/assets/console-overview-light.png">
</picture>

| Function invocations | Authentication |
| --- | --- |
| <picture><source media="(prefers-color-scheme: dark)" srcset="docs/assets/console-invocations-dark.png"><img alt="Every function call with its trigger, outcome and duration" src="docs/assets/console-invocations-light.png"></picture> | <picture><source media="(prefers-color-scheme: dark)" srcset="docs/assets/console-auth-dark.png"><img alt="Authentication: users with filters, one open with its profile, security and providers" src="docs/assets/console-auth-light.png"></picture> |
| **Firestore** | **Storage** |
| <picture><source media="(prefers-color-scheme: dark)" srcset="docs/assets/console-firestore-dark.png"><img alt="Firestore: collections, a page of orders and one open for editing" src="docs/assets/console-firestore-light.png"></picture> | <picture><source media="(prefers-color-scheme: dark)" srcset="docs/assets/console-storage-dark.png"><img alt="Storage: a folder of product photos as a grid of thumbnails" src="docs/assets/console-storage-light.png"></picture> |

More in [the console guide](docs/console.md).

## Benchmarks

One server (a Ryzen 5 3600 with 64 GiB), one real application with 211,205
Firestore documents and 6.7 GB in Storage, and two hours of its traffic against
each emulator in turn. Then each emulator alone on the same data: starts,
stops, 26 query shapes and a store grown to 2.5 million documents.

<picture>
  <source media="(prefers-color-scheme: dark)" srcset="docs/assets/benchmark-dark.svg">
  <img alt="Firenook against the official emulator: 10 times less memory, writes 40 times faster, listener updates 19 times faster, restarts 52 times sooner, orderBy with a limit 8 times faster, 61% less CPU" src="docs/assets/benchmark-light.svg" width="880">
</picture>

Firenook answered 25 of the 26 query shapes faster and tied on the last, and
both gave the same answers. The method, every figure and the limits are in
[the benchmarks](docs/benchmarks.md).

## Get started

### Already using the Firebase emulator

**1. Install it** in the project, next to firebase-tools (keep that for
deploying):

```sh
npm install --save-dev firenook    # or: bun add --dev firenook
```

Commit the lockfile: it keeps every machine and CI run on the release you
installed, and the same engine, until you upgrade.

Every run keeps its working data under `.firenook/`, so add that folder to
your `.gitignore`.

**2. Check your project.** This reads `firebase.json` the way the Firebase CLI
does and changes nothing:

```console
$ npx firenook init --adopt --dry-run
  skip    Firenook: firebase.json configures the hosting emulator, which Firenook does not implement; skipping it.
  ok      nothing to change; services: firestore, auth, storage, functions
```

It names any service Firenook skips (Realtime Database, Hosting, App Hosting,
Data Connect) and any addition it would make, such as a missing `emulators`
entry; `npx firenook init --adopt` applies those additions.

**3. Swap the command.** Same flags, same ports, and the same export format, so
your existing data imports as it is:

```diff
 "scripts": {
-  "emulators": "firebase emulators:start --import ./data --export-on-exit",
-  "test:integration": "firebase emulators:exec \"npm test\""
+  "emulators": "firenook emulators:start --import ./data --export-on-exit",
+  "test:integration": "firenook emulators:exec \"npm test\""
 }
```

Your app connects to the same ports as before, so no code changes:
`connectFirestoreEmulator(db, '127.0.0.1', 8080)`, `FIRESTORE_EMULATOR_HOST`
and the rest work unchanged.

**4. Optionally, stop exporting at every stop.** In place of
`--export-on-exit`, add `--keep-data` and Firenook keeps your data between runs
in `.firenook/state`. Every start after the first picks the data up where you
left it, and `./data` itself stays untouched:

```sh
npx firenook emulators:start --import ./data --keep-data
```

Going back is just as short: stop Firenook (it saves first), export with
`npx firenook emulators:export ./export`, and start the official CLI on that
export.

### Starting a new project

```sh
npx firenook init
```

<p align="center">
  <img alt="firenook init: a screen of choices already made, the set-up as it runs, and the emulators started in the same terminal" src="docs/assets/init.gif" width="760">
</p>

In a terminal, `init` opens on one screen with every choice already made:
a `demo-<folder>` project, so nothing can reach a real Firebase project,
every emulator on its usual port (one already in use is named, with what
holds it), Functions in TypeScript, JavaScript or none, and the coding agents
it finds. Enter takes them all. It then writes the official templates,
installs the packages, pins Firenook in `package.json`, builds the
TypeScript once, and starts the emulators in the same terminal. From then on:

```sh
npm run emulators            # firenook emulators:start --keep-data --build
```

A new project keeps its data between runs from the first start, and
`--build` compiles your TypeScript as you save, with the errors in the log.
In a script or CI, `npx firenook init --yes` does the same with no questions.
Point your app at it:

```js
connectFirestoreEmulator(db, '127.0.0.1', 8080);
connectAuthEmulator(auth, 'http://127.0.0.1:9099');
connectStorageEmulator(storage, '127.0.0.1', 9199);
connectFunctionsEmulator(functions, '127.0.0.1', 5001);
```

Firenook needs Node 22, 24 or 26 on macOS, Linux (glibc 2.28 or newer, so
RHEL 8, Debian 10, Ubuntu 20.04, node:24-slim and later; not Alpine) or
Windows x64. The [getting started guide](docs/getting-started.md) covers each
step in more
depth, including tests and keeping data.

## Documentation

- [Getting started](docs/getting-started.md) · [The terminal](docs/terminal.md)
  · [The console](docs/console.md) · [Configuration](docs/configuration.md)
- [Functions and Extensions](docs/functions-and-extensions.md) ·
  [Data, state and tests](docs/data-and-state.md) ·
  [Model Context Protocol](docs/mcp.md) · [CLI reference](docs/cli.md)
- [Benchmarks](docs/benchmarks.md) · [Compatibility](COMPATIBILITY.md) ·
  [Versions and verification](docs/versions-and-verification.md) ·
  [Roadmap](ROADMAP.md) · [Design](DESIGN.md)

## Status

Firenook 0.2.0 is the first stable release. Every release passes conformance
replays against the official emulator and packed installs on all five
platforms, and releases are measured against the official emulator with a
real application (most recently 0.2.0, in the
[benchmarks](docs/benchmarks.md)). Commit your lockfile and upgrade on
purpose; [the releases](https://github.com/firenook-dev/firenook/releases) list
what each one carries.

## Contributing

Firenook is built in the open under the Apache License 2.0.
[CONTRIBUTING.md](CONTRIBUTING.md) explains how a change moves, from a
recorded fixture of the official emulator to a release, and how to build and
test from source. Report a bug or ask for a feature in the
[issues](https://github.com/firenook-dev/firenook/issues).

## License and trademarks

Firenook is licensed under the [Apache License 2.0](LICENSE); see
[NOTICE](NOTICE) for the reference-only sources studied and
[TRADEMARKS.md](TRADEMARKS.md) for the use of the Firenook name and mark.
Firebase, Cloud Firestore, Cloud Functions, Cloud Storage, Cloud Pub/Sub and
Cloud Tasks are trademarks of Google LLC. Firenook is not affiliated with or
endorsed by Google.

TDQS

B3.4/5.0

Scored across 54 tools

Disambiguation4/5

Tools are grouped by service prefix (firestore_, auth_, storage_, pubsub_, tasks_, schedules_, eventarc_, functions_, rules_, logs_, extensions_, emulators_) and each action within a group is distinct (get vs query vs count, copy vs move, list vs get_call). A few pairs could still be confused at a glance: auth_mint_token vs auth_set_claims (token-only claims vs stored custom claims), pubsub_peek vs pubsub_list_subscriptions (both expose backlog), and firestore_delete vs emulators_clear (scoped vs global destructive wipe). These are resolved by the descriptions, so ambiguity is minor rather than systemic.

Naming Consistency4/5

Names follow a predictable service_verb_noun snake_case pattern (firestore_get, auth_list_users, storage_upload, functions_replay_call), which makes the set easy to scan and predict. A handful of deviations drop the verb (auth_oob_codes, auth_verification_codes, tasks_stats) and a few are noun-first (firestore_list_collections, functions_list_calls), but the service prefix keeps everything readable.

Tool Count3/5

54 tools is heavy by any standard, though the surface genuinely spans a dozen Firebase sub-domains (Firestore, Auth, Storage, Pub/Sub, Tasks, Schedules, Eventarc, Functions, Rules, Logs, Extensions, Emulators), averaging ~4-5 tools each. Per-domain scope is tight, but the overall count makes discovery and selection cost high for an agent. It sits at the borderline of 'large but justified' rather than clearly well-scoped.

Completeness4/5

Coverage is unusually deep: full CRUD for Firestore documents, Auth users, Storage objects, plus inspection/replay for functions, Eventarc events, scheduled runs, rules evaluation and logs. Notable gaps remain: no user profile update (email/password/display name), no Pub/Sub topic/subscription creation or message pull/ack, no rules deployment (rules_get is read-only), and no emulator start/stop/import to pair with emulators_export and emulators_clear. Most gaps are workaroundable but some block common emulator-management workflows.

Maintenance

ActivityActive
ResponsivenessNo recent community issues