A faster Firestore emulator

Firenook’s Firestore emulator answers the same SDKs on the same port, enforces your Security Rules, and imports the export you have. Writes are 40× faster, it uses 10× less memory, it needs no Java, and your data is still there after a restart.

npm install --save-dev firenook
Read the Firestore docs
Firenook’s console on Firestore: the collections, a page of orders and one order open for editing

Measured on a real application

Two hours of a production app’s traffic against each emulator in turn, every write and listener update timed by the client.

Memory at peak

10× less

Official
22.6 GiB
Firenook
2.11 GiB

Write, median

40× faster

Official
208 ms
Firenook
5.1 ms

Listener update, median

19× faster

Official
209 ms
Firenook
11 ms

Restart with data kept

52× sooner

Official
30.8 s
Firenook
0.59 s

Firenook against firebase-tools 15.22.0 on Java 26, on one AMD Ryzen 5 3600 server with 64 GiB, with a real application with 211,205 Firestore documents and 6.7 GB in Storage. Every result and how it was measured.

The Firestore your app already talks to

Firenook implements Firestore’s protocols and its rules engine itself, checked against the official emulator’s answers, so your SDKs and tests find what they expect.

  • Every SDK, unchanged

    The native and Admin SDKs over gRPC, the web SDK over WebChannel, and REST, on port 8080 or the port firebase.json gives it.

  • Realtime listeners

    Snapshots, queries and their updates as the SDKs expect them. A listener heard a write in 11 ms at the median, against 209 ms.

  • Security Rules, reloaded as you save

    Each database’s rules file is installed a second after you save it, and a denial names the rule line that decided it. A file that does not compile leaves the rules in force and says why.

  • Named databases

    Every database your app names, exported together. A database firebase.json does not list follows the default database’s rules. The official emulator refuses more than one.

  • The official export format

    --import takes the export you already have, and emulators:export writes one the official emulator can import, every database included.

  • Data on disk

    Data lives on disk and memory caches what you read. Every acknowledged write is on disk within a second, so a crash loses at most that second.

Every production feature, edition or client version is not claimed. What Firestore covers in 0.2.0, and the release’s known issues.

Restart in half a second, with your data

Add --keep-data and Firestore comes back with every document in about half a second, however many there are. No export at every stop, no import at every start.

npx firenook emulators:start --keep-data

Official emulator

Stop: export, 50–57 sStart: import, 21.6–23.6 s

Firenook

Stop, 0.04–0.30 sStart, 0.54–0.57 s

Stopping with the data saved, then starting again with it, on one time scale. The dim blocks are the spread between the fastest and the slowest runs.

Ordered queries from an index

orderBy, range filters and cursors walk an ordered index to the documents asked for. On a store of 2.7 million documents each answered in 3 to 6 ms, where the official emulator needed a 24 GiB heap and 8 to 28 seconds.

Query shape, 10,918 documentsOfficialFirenook
orderBy an integer field, limit 2096.3 ms12.0 ms
Range on an integer field, limit 2095.5 ms13.2 ms
== plus orderBy on another field99.3 ms14.7 ms
Five cursor pages of 20489 ms74.8 ms
orderBy a timestamp, descending, limit 20109 ms24.7 ms

Medians over gRPC, every answer identical on both. Equality filters on other fields are checked against the index before a document is read. All 26 shapes.

Questions

The rest is in the Firestore docs. Something else? Ask on GitHub.

Does my app need to change?

No. connectFirestoreEmulator(db, "127.0.0.1", 8080), FIRESTORE_EMULATOR_HOST and the rest connect as they do to the official emulator, on the port firebase.json gives Firestore.

Can I run Firestore on its own?

Yes: npx firenook emulators:start --only firestore. To keep your data between runs with --keep-data, run Auth and Storage with it; the kept data covers all three.

How much memory does it use?

In the benchmark, 2.11 GiB at most over two hours of an application’s traffic, against 22.57 GiB for the official emulator, and 0.16 GiB once ready with 211,205 documents.

Is the official emulator faster at anything?

Not in the benchmark. Of the 26 query shapes measured, Firenook was faster on 25 and tied on the last, ids only, limit 500: it reads each document whole before dropping its fields.

Can I go back to the official emulator?

Yes. Export with npx firenook emulators:export ./export while Firenook runs, and start the official emulator with --import ./export.

Does it need Java?

No. Firestore is native code in the one npm package, with an engine for macOS, Linux and Windows. Nothing else is downloaded.

Switch your Firestore emulator

Install Firenook next to firebase-tools, and change firebase to firenook in your emulator script. Your rules, indexes, data and app stay as they are.

npx firenook emulators:start
Switch in three steps