DEV Community

Cover image for Seeding mock data to the Firebase Local Emulator Suite
Seth Hall
Seth Hall

Posted on • Updated on

Seeding mock data to the Firebase Local Emulator Suite

I have recently been working on a React/Firebase side project to level up my skills and provide a playground to experiment with different techniques, patterns and libraries. One of my favorite features in Firebase is the Local Emulator Suite.

The Firebase Local Emulator Suite is a set of advanced tools for developers looking to build and test apps locally using Cloud Firestore, Realtime Database, Authentication, Cloud Functions, Pub/Sub, and Firebase Hosting. It provides a rich user interface to help you get running and prototyping quickly.

The Local Emulator Suite is fairly easy to set up but be sure to reference the docs for full details.

Regarding the actual code in your project, you first need to make sure the emulator ports are defined in your firebase.json file like so ...

firebase.json
Enter fullscreen mode Exit fullscreen mode
"emulators": {
  "auth": {
    "port": 9099
  },
  "firestore": {
    "port": 8080
  },
  "ui": {
    "enabled": true,
    "port": 4000
  }
}
Enter fullscreen mode Exit fullscreen mode

Then in your app's firebase.js file, include an if statement that checks your Node environment. If you are in 'development' mode your app will automatically run against the emulators and will use the ports that you defined in your firebase.json file.

firebase.js
Enter fullscreen mode Exit fullscreen mode
import firebase from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';

export const firebaseConfig = {
  apiKey: process.env.REACT_APP_FIREBASE_API_KEY,
  authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN,
  databaseURL: process.env.REACT_APP_FIREBASE_DATABASE_URL,
  projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
  storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
  messagingSenderId: process.env.REACT_APP_FIREBASE_MESSAGING_SENDER_ID,
  appId: process.env.REACT_APP_FIREBASE_APP_ID,
  measurementId: process.env.REACT_APP_FIREBASE_MEASUREMENT_ID
};

if (!firebase.apps.length) {
  firebase.initializeApp(firebaseConfig);
}

const app = firebase.app();
const auth = firebase.auth();
const db = firebase.firestore();

if (process.env.NODE_ENV === 'development') {
  console.log('testing locally -- hitting local auth and firestore emulators');
  auth.useEmulator('http://localhost:9099/');
  db.useEmulator('localhost', 8080);
}

console.log(app.name ? 'Firebase Mode Activated!' : 'Firebase not working :(');
Enter fullscreen mode Exit fullscreen mode

Now navigate to the root of your project in your terminal and start the emulators by running firebase emulators:start. You should see this in your terminal

image

and the Emulator UI at http://localhost:4000

emulator-console

Now that you have emulators set up and running, it is time to seed the data to Firestore to develop against.

Seeding Data to Firestore Local Emulator

When developing locally it is helpful to have a data set to work with. While there are a few approaches to seeding data, including this approach via the Firebase docs, I chose to go with a simple script.

Create a script in your project root called dbseed.js.

dbseed.js
Enter fullscreen mode Exit fullscreen mode
const admin = require('firebase-admin'); // required
const faker = require('faker'); // amazing library!

// initialization
const projectId = 'your-firebase-project-id';
process.env.FIRESTORE_EMULATOR_HOST = 'localhost:8080';
admin.initializeApp({ projectId });

const db = admin.firestore();

// seed function
function getSeedData() {
  try {
    [...Array(10).keys()].map(() =>
      db.collection('events').add({
        author_name: faker.name.firstName() + '' + faker.name.lastName(),
        author_profile_pic: faker.image.imageUrl(),
        title: faker.commerce.productName(),
        description: faker.commerce.productDescription(),
        address: {
          addr_1: faker.address.streetAddress(),
          addr_2: faker.address.secondaryAddress(),
          city: faker.address.city(),
          state: faker.address.state(),
          zipCode: faker.address.zipCode()
        }
      })
    );
    console.log('database seed was successful');
  } catch (error) {
    console.log(error, 'database seed failed');
  }
}

getSeedData();

Enter fullscreen mode Exit fullscreen mode

This script contains the required imports and initialization and runs a function that writes an array of objects to an 'events' collection.

Once the emulator suite is running, navigate to Firestore Emulator UI then run node dbseed.js in a separate terminal window/tab.

You will see that the empty Firestore db is seeded with an array of Faker objects. Faker.js is an amazing library. Be sure to check out all the options at the https://github.com/marak/Faker.js/

Seed mock data to the Firebase Local Emulator Suite

Success! Now you can develop against test data while work within the Firebase Local Emulator Suite.

What about working with real production data?

You can also work with your production data if that is a better fit. Set up is more involved but still a nice approach. Check out the Firestore Docs to learn how to export your production data then import it when starting the emulators.

Conclusion

Working with mock data is an essential part of development and is something that I struggled with when working in the Firebase Local Emulator Suite. This simple approach allows me to seed the database quickly. Thanks for reading and I hope this helps your workflow. Happy coding!

Top comments (6)

Collapse
 
nickytonline profile image
Nick Taylor

Congrats on your first post!

You did it!

Collapse
 
markgoho profile image
Mark Goho

@sethburtonhall wondering if you considered using the @firebase/rules-unit-testing library for seeding data.

Collapse
 
sethburtonhall profile image
Seth Hall

I haven't, will look into it though. Thanks!

Collapse
 
drewclem profile image
Drew Clements

Fantastic!

Collapse
 
qualleadmin profile image
Qualle

this gives me an 'app/invalid-credential' error. I've never understood how to do initializeApp with a local emulator, how can you provide a projectId if its a local emulator?

Collapse
 
th0rgall profile image
Thor Galle • Edited

I was also wrestling with this. I haven't tested it, but I suspect this post uses real credentials and a real Firebase project, which is initialized with firebase login or firebase use.

In my case, I wanted to seed a "demo-" project that can not connect to real services (the docs on demo- projects are vague and scattered). I was getting invalid (default) credential errors too when trying to connect to my emulators via a separate Node.js script.

What worked for my demo-test project was:

dbseed.js

  • add a a #!/usr/bin/env node shebang on top.
  • add a process.stdin.resume(); line on the bottom to prevent the seed process from exiting (because emulators:exec below would otherwise kill the emulators after the seeding is done, see below).
  • initialize as follows:
const admin = require('firebase-admin');
const app = admin.initializeApp({
  projectId: 'demo-test'
});
const db = admin.firestore(app);
const auth = admin.auth(app);
Enter fullscreen mode Exit fullscreen mode

It proved important to not try to call db.settings({...}) with the host of my local Firestore Emulator etc, I suppose these should be automagically configured by the environment variables exported by the Firebase Emulator.

Execution

firebase --project demo-test emulators:exec --ui dbseed.js
Enter fullscreen mode Exit fullscreen mode

This executes the seed script with credentials available from the context.