Skip to content

Ports

Firenook listens on the same ports as the official emulators, so your app and tools need no change. This page lists every listener, how to move it, and what Firenook does when a port is already in use.

Listener Default firebase.json key Flag Runs when
Firestore 8080 emulators.firestore.port Firestore runs
Firestore requests WebSocket 9150 emulators.firestore.websocketPort --firestore-websocket-port Firestore runs
Authentication 9099 emulators.auth.port Auth runs
Cloud Storage 9199 emulators.storage.port Storage runs
Cloud Functions 5001 emulators.functions.port Functions runs
Eventarc 9299 emulators.eventarc.port --eventarc-port Functions runs
Cloud Tasks 9499 emulators.tasks.port --tasks-port Functions runs
Pub/Sub 8085 emulators.pubsub.port Pub/Sub runs
Hub 4400 emulators.hub.port --hub-port Always
Console (the Emulator UI port) 4000 emulators.ui.port The UI is on
Logging 4500 emulators.logging.port --logging-port The UI is on

A flag wins over firebase.json, and firebase.json over the default. The emulators with no flag in the table take their port from firebase.json only. Each listener serves what its official counterpart serves: gRPC and REST on the same Firestore and Pub/Sub ports, the console and /api/config on the UI port, and the hub’s /emulators listing and export routes on the hub port. The Firestore WebSocket carries the Firestore requests feed for tools that read it, and the logging listener carries the log stream the old Emulator UI read.

Functions workers started with --inspect-functions also open the Node inspector, on 9229 for the first codebase and the next port for each further one. --inspect-functions=9230 starts from the port you give. An Extension instance is a codebase too, and when one is configured it takes the first port, so your own code gets the next one. See Debugging.

A typical firebase.json with every port named:

firebase.json
{
"emulators": {
"auth": { "port": 9099 },
"functions": { "port": 5001 },
"firestore": { "port": 8080, "websocketPort": 9150 },
"pubsub": { "port": 8085 },
"storage": { "port": 9199 },
"eventarc": { "port": 9299 },
"tasks": { "port": 9499 },
"hub": { "port": 4400 },
"logging": { "port": 4500 },
"ui": { "enabled": true, "port": 4000 }
}
}

The ports must all be different, including the defaults of emulators you do not start. A clash stops Firenook before anything listens:

Terminal window
$ npx firenook emulators:start --hub-port 9099
Firenook: Emulator ports must be distinct

The default host is localhost, bound as the official CLI binds it:

  • Firestore, its WebSocket, Auth, Storage, Functions, Eventarc, Cloud Tasks, Pub/Sub and the logging listener listen on 127.0.0.1.
  • The hub and the console listen on 127.0.0.1 and on ::1, so http://localhost:4000/console opens whichever address your browser tries first.

An emulator’s own port therefore refuses http://[::1]:8080, as it does with the official CLI, and every address Firenook gives your app, your tests and the Connect dialog is 127.0.0.1. A port that is free on 127.0.0.1 but taken on ::1 is a warning, not an error.

--host or emulators.<name>.host chooses another address, and an address you name is that address alone: --host ::1 puts every listener on the IPv6 loopback. Firenook listens on one host for all of them: an emulators.<name>.host that differs from the others is an error, unless it is a loopback address.

With --host 0.0.0.0 (or ::) the emulators listen on every network interface, and the addresses Firenook gives your app, your tests and the Connect dialog use 127.0.0.1 (or ::1). Any other host than loopback prints a warning, because the emulators have no authentication:

Firenook: binding 0.0.0.0; the emulators have no authentication, so every service, the data and arbitrary Functions execution are reachable from any device that can reach this host.

The console has its own check on the host names it answers for; see The console.

  • The terminal’s ready summary lists them, with the console’s address.
  • /api/config on the UI port answers with every emulator’s host and port, as the official Emulator UI’s does.
  • The hub’s /emulators route answers the same listing.
  • The console’s Connect dialog prints the emulators block of firebase.json for the ports in use.
  • The MCP tool firenook_status returns them to a coding agent.

A running suite also records its hub’s address in hub-<project>.json in the system’s temporary folder, as the official emulators do. emulators:export, firestore:delete, functions:invoke and firenook mcp find the suite through that file, so they work even when the ports differ from firebase.json.

When a port is in use, Firenook stops, says which program holds it, and leaves your data as it was. In a terminal:

├─ ✕ Firenook could not start ─────────────────────────────────────────────────────┤
│ │
│ Problem port 38212 for Auth is held by firenook (PID 94724): another │
│ Firenook │
│ │
│ Fix stop it: kill 94724 │
│ or give Auth a free port in firebase.json: │
│ "emulators": { "auth": { "port": 38218 } } │
│ │
│ Data nothing of yours was changed │
│ │
╰──────────────────────────────────────────────────────────────────────────────────╯

The suggested port is a free one at the time. In plain output:

suite failed: cannot bind auth at 127.0.0.1:38212: Address already in use (os error 48)

Either way the command exits with code 1. Firenook never stops the other program for you.

Give each suite its own ports in its own firebase.json, every listener included. The two may share a project id, such as two checkouts of one project. The second one to start warns, as the official CLI does, and both run and stop cleanly:

firenook: It seems that you are running multiple instances of the emulator suite for project demo-shop. This may result in unexpected behavior. Firenook commands run in this project's folder still reach this suite (elsewhere, pass --hub-port 4415); the official CLI reaches the other one.

The hub-<project>.json file names one suite per project id, the first one started, and the official CLI’s commands reach that one. Firenook’s commands (emulators:export, firestore:delete, functions:invoke, firenook mcp) reach the suite started from the folder they run in, or a folder inside it. Run from another folder, they need --hub-port to choose one, and without it they name both suites and exit 1:

Terminal window
$ npx firenook firestore:delete orders -r -f --json --project demo-shop
Firenook: 2 suites run for demo-shop (http://127.0.0.1:4400 from ~/demo-shop, http://127.0.0.1:4415 from ~/demo-shop-copy); run the command in the project's folder, or pass --hub-port <port> to choose one
$ npx firenook firestore:delete orders -r -f --json --project demo-shop --hub-port 4415
{"path":"orders","mode":"recursive","deleted":2}

Configuration covers the rest of firebase.json, and Run one service on its own starts a subset of the emulators.