Firebase Emulator Suite

The Firebase Emulator Suite runs local versions of Firebase services on your development machine. You test Firestore, Authentication, Cloud Functions, Storage, and more without touching your production data or incurring costs. Changes made to the emulator disappear when you stop it, making it safe for experimental testing.

Why Use the Emulator

Testing against production Firebase services has three problems: it modifies real data, it incurs usage costs, and it is slow due to network latency. The emulator solves all three:

Without Emulator:
Test creates a user ---> Production Firebase Auth gets a real user
Test writes data    ---> Production Firestore gets test records
Test triggers function ---> Real Cloud Function runs, billing counts
Result: Production polluted with test data, money spent

With Emulator:
Test creates a user ---> Local Auth emulator only
Test writes data    ---> Local Firestore emulator only
Test triggers function ---> Local Functions emulator
Result: No production impact, no cost, instant response

Installing the Emulator Suite

# Firebase CLI must be installed
npm install -g firebase-tools

# Initialize emulators in your project
firebase init emulators

Firebase asks which emulators to install:

  • Authentication Emulator — port 9099
  • Firestore Emulator — port 8080
  • Realtime Database Emulator — port 9000
  • Cloud Functions Emulator — port 5001
  • Storage Emulator — port 9199
  • Hosting Emulator — port 5000
  • Pub/Sub Emulator — port 8085

Select the ones you need. Firebase adds an emulators section to your firebase.json.

Starting the Emulators

firebase emulators:start

The terminal shows each emulator starting on its port. A local Emulator UI opens at http://localhost:4000 — a browser-based dashboard where you browse data, view function logs, and manage auth users.

Firebase Emulators:
┌────────────────────────┬───────────────────────────────┐
│ Emulator               │ Host:Port                     │
├────────────────────────┼───────────────────────────────┤
│ Authentication         │ localhost:9099                │
│ Firestore              │ localhost:8080                │
│ Cloud Functions        │ localhost:5001                │
│ Storage                │ localhost:9199                │
│ Emulator UI            │ localhost:4000                │
└────────────────────────┴───────────────────────────────┘

Connecting Your App to the Emulators

Tell your app to use the local emulators instead of production Firebase services:

import { initializeApp } from "firebase/app";
import { getAuth, connectAuthEmulator } from "firebase/auth";
import { getFirestore, connectFirestoreEmulator } from "firebase/firestore";
import { getFunctions, connectFunctionsEmulator } from "firebase/functions";
import { getStorage, connectStorageEmulator } from "firebase/storage";

const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const db = getFirestore(app);
const functions = getFunctions(app);
const storage = getStorage(app);

// Only connect to emulators in development
if (process.env.NODE_ENV === "development") {
  connectAuthEmulator(auth, "http://localhost:9099");
  connectFirestoreEmulator(db, "localhost", 8080);
  connectFunctionsEmulator(functions, "localhost", 5001);
  connectStorageEmulator(storage, "localhost", 9199);
}

All Firebase calls from your app now go to the local emulators. Production data is untouched.

Importing and Exporting Emulator Data

Seed the emulator with test data from a file so every test run starts with a consistent state:

# Export current emulator data to a folder
firebase emulators:export ./emulator-data

# Start emulators with data pre-loaded
firebase emulators:start --import=./emulator-data

Create a seed script that populates the emulator with realistic test data — a few users, some posts, sample settings — and export it once. Every developer on your team imports the same data for consistent testing.

Testing Security Rules with the Emulator

The emulator enforces your actual security rules from firestore.rules and storage.rules. Write automated rule tests:

const { initializeTestEnvironment } = require("@firebase/rules-unit-testing");

const testEnv = await initializeTestEnvironment({
  projectId: "my-project",
  firestore: {
    rules: require("fs").readFileSync("firestore.rules", "utf8"),
    host: "localhost",
    port: 8080
  }
});

// Test as an authenticated user
const aliceDb = testEnv.authenticatedContext("alice_uid").firestore();
// Write should succeed — Alice can write her own document
await firebase.assertSucceeds(
  aliceDb.collection("users").doc("alice_uid").set({ name: "Alice" })
);

// Test as an unauthenticated user
const unauthDb = testEnv.unauthenticatedContext().firestore();
// Write should fail — unauthenticated users cannot write user documents
await firebase.assertFails(
  unauthDb.collection("users").doc("alice_uid").set({ name: "Fake Alice" })
);

Key Takeaway

The Firebase Emulator Suite provides local versions of every Firebase service for safe, free, fast development testing. Start emulators with firebase emulators:start, connect your app using the connect*Emulator functions in development mode, and use the Emulator UI to inspect data and logs. Export realistic seed data once and import it on every emulator start for consistent test conditions. Write automated security rule tests using the rules testing library against the local Firestore emulator.

Leave a Comment

Your email address will not be published. Required fields are marked *