Skip to main content
RapidDev - Software Development Agency
firebase-tutorial

How to Use Firebase Emulator Suite

The Firebase Emulator Suite lets you run Firestore, Auth, Functions, Storage, and Realtime Database locally so you can develop and test without touching production data or incurring costs. Install the Firebase CLI, run firebase emulators:start, connect your app code with the connectEmulator helpers, and use the Emulator UI at localhost:4000 to inspect data and manage users.

What you'll learn

  • How to install and configure the Firebase Emulator Suite
  • How to connect your web app to local emulators instead of production
  • How to use the Emulator UI to browse data and manage test users
  • How to export and import emulator data between sessions
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner7 min read10-15 minFirebase CLI 13+, Firebase JS SDK v9+, Node.js 18+March 2026RapidDev Engineering Team
TL;DR

The Firebase Emulator Suite lets you run Firestore, Auth, Functions, Storage, and Realtime Database locally so you can develop and test without touching production data or incurring costs. Install the Firebase CLI, run firebase emulators:start, connect your app code with the connectEmulator helpers, and use the Emulator UI at localhost:4000 to inspect data and manage users.

Running Firebase Services Locally with the Emulator Suite

The Firebase Emulator Suite provides local versions of Firestore, Auth, Cloud Functions, Storage, Realtime Database, Hosting, and Pub/Sub. You develop against these local services instead of production, which means zero billing impact and the ability to test security rules, triggers, and auth flows in isolation. This tutorial covers setup, connection, the Emulator UI dashboard, and persisting data across restarts.

Prerequisites

  • Firebase CLI installed (npm install -g firebase-tools) and logged in (firebase login)
  • A Firebase project initialized in your directory (firebase init)
  • Java JDK 11+ installed (required by the Firestore and Realtime Database emulators)
  • Node.js 18+ installed

Step-by-step guide

1

Initialize emulators in your project

Run the Firebase init command and select the emulators you want. This creates or updates firebase.json with emulator port configuration. Select at least Firestore, Auth, and Functions for a typical web app. Each emulator runs on a default port that you can customize.

typescript
1firebase init emulators
2
3# Select: Firestore, Auth, Functions, Storage
4# Accept default ports or customize:
5# Firestore: 8080
6# Auth: 9099
7# Functions: 5001
8# Storage: 9199
9# Emulator UI: 4000

Expected result: firebase.json includes an emulators block with ports for each selected service.

2

Start the emulators

Run the start command to launch all configured emulators. The terminal will display each emulator's URL and port. The Emulator UI launches at localhost:4000 by default and provides a visual dashboard for browsing Firestore documents, managing Auth users, and viewing Function logs.

typescript
1firebase emulators:start

Expected result: All selected emulators are running and the Emulator UI is accessible at http://localhost:4000.

3

Connect your app to the emulators

In your app's Firebase initialization code, call the connect functions for each service you want to route to the local emulator. Wrap these calls in a conditional check so they only run during development. Each service has its own connect function: connectFirestoreEmulator, connectAuthEmulator, connectFunctionsEmulator, and connectStorageEmulator.

typescript
1// src/lib/firebase.ts
2import { initializeApp } from 'firebase/app'
3import { getFirestore, connectFirestoreEmulator } from 'firebase/firestore'
4import { getAuth, connectAuthEmulator } from 'firebase/auth'
5import { getFunctions, connectFunctionsEmulator } from 'firebase/functions'
6import { getStorage, connectStorageEmulator } from 'firebase/storage'
7
8const app = initializeApp({ /* your config */ })
9
10export const db = getFirestore(app)
11export const auth = getAuth(app)
12export const functions = getFunctions(app)
13export const storage = getStorage(app)
14
15if (import.meta.env.DEV) {
16 connectFirestoreEmulator(db, '127.0.0.1', 8080)
17 connectAuthEmulator(auth, 'http://127.0.0.1:9099')
18 connectFunctionsEmulator(functions, '127.0.0.1', 5001)
19 connectStorageEmulator(storage, '127.0.0.1', 9199)
20}

Expected result: All Firebase SDK calls in your app now route to the local emulators when running in development mode.

4

Create test data and users in the Emulator UI

Open http://localhost:4000 in your browser. The Firestore tab lets you create collections and documents manually. The Auth tab lets you add test users with email/password, set custom claims, and generate auth tokens. The Functions tab shows live logs from your Cloud Functions. Use these tools to set up test scenarios without writing seed scripts.

Expected result: Test users and documents appear in the Emulator UI and are accessible from your running app.

5

Export and import emulator data

By default, emulators clear all data when stopped. Use the export flag to save state to a directory, and the import flag to restore it on the next start. This lets you build up a test dataset once and reuse it across development sessions.

typescript
1# Export data when stopping
2firebase emulators:start --export-on-exit=./emulator-data
3
4# Import data on next start
5firebase emulators:start --import=./emulator-data

Expected result: Emulator data persists between sessions when using the import and export flags.

6

Test security rules against the emulators

The emulators enforce your Firestore and Storage security rules, making them ideal for testing access control. Install the @firebase/rules-unit-testing package and write test cases that use assertSucceeds and assertFails to verify your rules allow and deny the correct operations.

typescript
1npm install --save-dev @firebase/rules-unit-testing
2
3// tests/firestore.rules.test.ts
4import { assertSucceeds, assertFails, initializeTestEnvironment } from '@firebase/rules-unit-testing'
5import { readFileSync } from 'fs'
6
7const testEnv = await initializeTestEnvironment({
8 projectId: 'test-project',
9 firestore: {
10 rules: readFileSync('firestore.rules', 'utf8'),
11 host: '127.0.0.1',
12 port: 8080
13 }
14})
15
16const authedContext = testEnv.authenticatedContext('user-123')
17const unauthedContext = testEnv.unauthenticatedContext()
18
19await assertSucceeds(
20 authedContext.firestore().collection('posts').doc('test').get()
21)
22
23await assertFails(
24 unauthedContext.firestore().collection('posts').doc('test').get()
25)

Expected result: Tests pass when rules correctly allow authenticated reads and deny unauthenticated reads.

Complete working example

src/lib/firebase.ts
1// src/lib/firebase.ts
2import { initializeApp } from 'firebase/app'
3import { getFirestore, connectFirestoreEmulator } from 'firebase/firestore'
4import { getAuth, connectAuthEmulator } from 'firebase/auth'
5import { getFunctions, connectFunctionsEmulator } from 'firebase/functions'
6import { getStorage, connectStorageEmulator } from 'firebase/storage'
7
8const firebaseConfig = {
9 apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
10 authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
11 projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
12 storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
13 messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
14 appId: import.meta.env.VITE_FIREBASE_APP_ID
15}
16
17const app = initializeApp(firebaseConfig)
18
19export const db = getFirestore(app)
20export const auth = getAuth(app)
21export const functions = getFunctions(app)
22export const storage = getStorage(app)
23
24// Connect to emulators in development
25if (import.meta.env.DEV) {
26 connectFirestoreEmulator(db, '127.0.0.1', 8080)
27 connectAuthEmulator(auth, 'http://127.0.0.1:9099')
28 connectFunctionsEmulator(functions, '127.0.0.1', 5001)
29 connectStorageEmulator(storage, '127.0.0.1', 9199)
30 console.log('Connected to Firebase Emulators')
31}

Common mistakes when using Firebase Emulator Suite

Why it's a problem: Calling connectEmulator functions after making a Firestore or Auth request, which throws 'Firestore has already been started'

How to avoid: Call all connectEmulator functions immediately after initializing the service, before any reads, writes, or auth calls. Place them right after getFirestore/getAuth in your initialization file.

Why it's a problem: Leaving emulator connection code active in production, routing all traffic to localhost

How to avoid: Always wrap connectEmulator calls in a DEV check (import.meta.env.DEV for Vite, process.env.NODE_ENV for Node). Double-check your production build does not include emulator connections.

Why it's a problem: Forgetting to install Java, causing the Firestore and Realtime Database emulators to fail to start

How to avoid: The Firestore and RTDB emulators require Java JDK 11+. Install it from adoptium.net or your system package manager and ensure java is available in your PATH.

Best practices

  • Use --export-on-exit and --import flags to persist test data between emulator sessions
  • Always use a DEV-only conditional to connect to emulators so production builds are never affected
  • Use 127.0.0.1 instead of localhost to prevent IPv6 resolution issues on macOS and Linux
  • Write security rules tests with @firebase/rules-unit-testing to catch permission bugs before deployment
  • Keep a small seed dataset in version control so all team members start with the same test data
  • Use the Emulator UI at localhost:4000 to inspect Firestore data and Function logs instead of adding console.log statements
  • Run emulators in CI pipelines to validate security rules and Cloud Functions as part of your test suite

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

Show me how to set up the Firebase Emulator Suite for a project that uses Firestore, Auth, and Cloud Functions. Include the firebase.json emulator config, the code to connect my app to emulators in development only, and how to export and import emulator data between sessions.

Firebase Prompt

Configure the Firebase Emulator Suite for my project. I need Firestore on port 8080, Auth on 9099, and Functions on 5001. Show me how to connect my web app to these emulators only during development and how to write a basic security rules test using @firebase/rules-unit-testing.

Frequently asked questions

Do emulators require a Firebase project or billing account?

No. Emulators run entirely on your local machine and do not connect to Google Cloud. You do not need a Blaze plan or any billing setup. You still need a firebase project ID in your config, but it can be a dummy value for local-only testing.

Does the Emulator Suite enforce security rules?

Yes. The Firestore and Storage emulators enforce your security rules files. The Auth emulator simulates authentication so your rules can check request.auth. This makes emulators ideal for testing access control before deploying.

Can I use emulators in a CI pipeline?

Yes. Run firebase emulators:exec 'npm test' to start emulators, run your test command, and shut down emulators automatically. This is the recommended approach for CI environments.

Why does my emulator data disappear when I stop the process?

By default, emulators clear all data on shutdown. Use --export-on-exit=./emulator-data to save state automatically, and --import=./emulator-data on the next start to restore it.

Can I run only specific emulators instead of all of them?

Yes. Use firebase emulators:start --only firestore,auth to start specific emulators. This is faster when you only need to test certain services.

How do I access the Emulator UI?

Open http://localhost:4000 in your browser after running firebase emulators:start. The UI provides tabs for each running emulator where you can browse Firestore data, manage Auth users, view Function logs, and inspect Storage files.

Are there differences between the emulator and production?

Emulators do not enforce billing quotas, rate limits, or all production constraints. Some features like full-text search in Data Connect and certain Cloud Function triggers may behave differently. Always run final validation against a staging Firebase project.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.