Google is committed to advancing racial equity for Black communities. See how.

Getting started with the Firebase Local Emulator Suite

Serverless backend tools like Cloud Firestore and Cloud Functions are very easy to use, but can be hard to test. The Firebase Local Emulator Suite allows you to run local versions of these services on your development machine so you can develop your app quickly and safely.

What you'll need

What you'll build

In this codelab, you run and debug a simple online shopping app which is powered by multiple Firebase services:

  • Cloud Firestore: A globally scalable, serverless, NoSQL database with real-time capabilities.
  • Firebase Hosting: A fast and secure hosting for web apps.
  • Cloud Functions: A serverless backend code that runs in response to events or HTTP requests.

You will connect the app to the Emulator Suite to enable local development.

What you'll learn

  • How to connect your app to the Emulator Suite.
  • How the various emulators are connected.

Create a Firebase project

If you don't have a Firebase project, in the Firebase console, create a new Firebase project. Make a note of the Project ID you choose, you will need it later.

Configure your project

In the Firebase console, navigate to the Authentication pane and then to the Sign-in method tab. Make sure the Anonymous provider is enabled.

Get the source code

In this codelab, you start off with a version of The Fire Store sample that is nearly complete, so the first thing you need to do is clone the source code:

$ git clone

Then move into the codelab directory, where you will work for the remainder of this codelab:

$ cd emulators-codelab/codelab-initial-state

Now, install the dependencies so you can run the code. If you're on a slower internet connection this may take a minute or two:

# Move into the functions directory, install dependencies, jump out.
$ cd functions && npm install && cd -

Get the Firebase CLI

The Emulator Suite is part of the Firebase CLI (command-line interface) which can be installed on your machine with the following command:

$ npm install -g firebase-tools

Next, confirm that you have the latest version of the CLI. This codelab should work with version 8.1.1 or higher but later versions include more bug fixes.

$ firebase --version

Connect to your Project

Now, link this code to your Firebase project. You can use any existing Firebase project for this codelab.

First run the following command to log in to the Firebase CLI:

$ firebase login

Next run the following command to create a project alias. First, select your project from the list. When asked what alias you want to use, choose default.

$ firebase use --add

The output should look like the following example. Remember to choose your actual Firebase project from the list:

? Which project do you want to add? YOUR_PROJECT_ID
? What alias do you want to use for this project? (e.g. staging) default

Created alias default for YOUR_PROJECT_ID.
Now using alias default (YOUR_PROJECT_ID)

Now you're ready to run the app!

In this section, you'll run the app locally. This means it is time to boot up the Emulator Suite.

Start the Emulators

From inside the codelab source directory, run the following command to start the emulators:

$ firebase emulators:start

You should see some output like this:

$ firebase emulators:start
i  emulators: Starting emulators: functions, firestore, hosting
i  firestore: downloading cloud-firestore-emulator-v1.11.5.jar...
Progress: ==================================================================================================================================================> (100% of 64MB
i  firestore: Removing outdated emulator files: cloud-firestore-emulator-v1.11.3.jar
i  firestore: Firestore Emulator logging to firestore-debug.log
i  hosting: Serving hosting files from: public
✔  hosting: Local server: http://localhost:5000
i  ui: downloading
Progress: ===================================================================================================================================================> (100% of 4MB
i  ui: Removing outdated emulator files: gui-v0.0.0-EAP
i  ui: Removing outdated emulator files:
i  ui: Emulator UI logging to ui-debug.log
i  functions: Watching "/usr/local/google/home/samstern/Scratch/emulator-codelabs/emulator-codelab/codelab-final-state/functions" for Cloud Functions...
✔  functions[calculateCart]: firestore function initialized.

│ ✔  All emulators ready! View status and logs at http://localhost:4000 │

│ Emulator  │ Host:Port      │ View in Emulator UI             │
│ Functions │ localhost:5001 │ http://localhost:4000/functions │
│ Firestore │ localhost:8080 │ http://localhost:4000/firestore │
│ Hosting   │ localhost:5000 │ n/a                             │
  Other reserved ports: 4400, 4500

Issues? Report them at and attach the *-debug.log files.

Once you see the All emulators started message, the app is ready to use.

Connect the web app to the Cloud Firestore Emulator

We can see that the Cloud Firestore emulator is serving web traffic on the port 8080 according to this line from the logs:

│ Firestore │ localhost:8080 │ http://localhost:4000/firestore

Let's connect your frontend code to the emulator, rather than to production. Open the public/js/homepage.js file and find the onDocumentReady function. You can see that the function accesses the standard Firestore instance:


  const db = firebaseApp.firestore();

Let's update the db object to point to the Firestore emulator:


  const db = firebaseApp.firestore();

  if (window.location.hostname === "localhost") {
    console.log("localhost detected!");
      host: "localhost:8080",
      ssl: false

Now when the app is running on localhost (served by the Hosting emulator) the Firestore client also points at the local emulator rather than at a production database.

In your web browser, navigate to http://localhost:4000/. You should see the Emulator Suite UI.

Click to see the UI for the Firestore Emulator. There's no data in the database yet, but leave this tab open and you can check back at any time to see what's been written to the Firestore Emulator.

Open the app

In your web browser, navigate to http://localhost:5000 and you should see The Fire Store running locally on your machine!

Visit the Firestore Emulator UI

In your web browser, refresh the Firestore Emulator UI, http://localhost:4000/firestore. You should see an Items collection; this was populated for demonstration purposes.

Add and remove items from the Firestore Emulator UI, and see those changes reflected in the storefront, http://localhost:5000.

[Optional] How do I know this is safe?

You might be worried that the codelab is actually writing data to your production database. This is not the case! All reads and writes are handled locally by the Cloud Firestore emulator. We can guarantee that this is the case using Security Rules.

If you created a new project for this codelab, navigate to the Database tab of the Firebase console, choose Firestore, and click Create Database. You'll be asked to choose a mode for your new Cloud Firestore database:

Choose production mode and continue. This means that your web app cannot read or write any data to your production database. Your app only communicates with the emulator. All of the data you're working with is 100% local and is erased when the emulator shuts down.

Use the app

Pick an item on the homepage and click Add to Cart. Unfortunately, you will run into the following error:

Let's fix that bug! Because everything is running in the emulators, we can experiment and not worry about affecting real data.

Find the bug

Ok let's look in the Chrome developer console. Press Control+Shift+J (Windows, Linux, Chrome OS) or Command+Option+J (Mac) to see the error on the console:

It seems like there was some error in the addToCart method, let's take a look at that. Where do we try to access something called uid in that method and why would it be null? Right now the method looks like this in public/js/homepage.js:


  addToCart(id, itemData) {
    console.log("addToCart", id, JSON.stringify(itemData));
    return this.db

Aha! We're not signed into the app. According to the Firebase Authentication docs, when we are not signed in, auth.currentUser is null. Let's add a check for that:


  addToCart(id, itemData) {
    if (this.auth.currentUser === null) {
      this.showError("You must be signed in!");

    // ...

Test the app

Now, refresh the page and then click Add to Cart. You should get a nicer error this time:

But if you click Sign In in the upper toolbar and then click Add to Cart again, you will see that the cart is updated.

However, it doesn't look like the numbers are correct at all:

Don't worry, we'll fix that bug soon. First, let's dive deep into what actually happened when you added an item to your cart.

Clicking Add to Cart kicks off a chain of events that involve multiple emulators. In the Firebase CLI logs, you should see something like the following messages after you add an item to your cart:

i  functions: Beginning execution of "calculateCart"
i  functions: Finished "calculateCart" in ~1s

There were four key events that occurred to produce those logs and the UI update you observed:

1) Firestore Write - Client

A new document is added to the Firestore collection /carts/{cartId}/items/{itemId}/. You can see this code in the addToCart function inside public/js/homepage.js:


  addToCart(id, itemData) {
    // ...
    console.log("addToCart", id, JSON.stringify(itemData));
    return this.db

2) Cloud Function Triggered

The Cloud Function calculateCart listens for any write events (create, update, or delete) that happen to cart items by using the onWrite trigger, which you can see in functions/index.js:


exports.calculateCart = functions.firestore
    .onWrite(async (change, context) => {
      try {
        let totalPrice = 125.98;
        let itemCount = 8;

        const cartRef = db.collection("carts").doc(context.params.cartId);

        return await cartRef.update({
      } catch(err) {

3) Firestore Write - Admin

The calculateCart function reads all of the items in the cart and adds up the total quantity and price, then it updates the "cart" document with the new totals (see cartRef.update(...) above).

4) Firestore Read - Client

The web frontend is subscribed to receive updates about changes to the cart. It gets a real-time update after the Cloud Function writes the new totals and updates the UI, as you can see in public/js/homepage.js:


this.cartUnsub = cartRef.onSnapshot(cart => {
   // The cart document was changed, update the UI
   // ...

Nice work! You just set up a fully local app that uses three different Firebase emulators for fully local testing.

But wait, there's more! In the next codelab you'll learn:

  • How to write unit tests that use the Firebase Emulators.
  • How to use the Firebase Emulators to debug your Security Rules.