DEV Community

Mario García
Mario García

Posted on

Local Firestore Development with the gcloud Emulator

Worked on a dashboard for a pharmacy, deployed on GitLab Pages, for which I chose the following stack:

  • React
  • TypeScript
  • Cloud Firestore

Previously used Firestore to enable Views and Likes for Blowfish, a Hugo theme I configured for my website. This time I needed a free cloud database solution to store information about:

  • Locations
  • Medicines
  • Orders
  • Sales
  • Users

On the free Spark Plan of Firebase, you can't create a second database within the same project if you're planning to use it for running tests against it instead of the default database. One workaround is to create a separate project, destined to be used for testing.

A better solution would be to use the Firestore Emulator, intended to use for local testing, provided by the Google Cloud CLI.

Install the emulator

Follow the instructions from the documentation.

  1. Install the gcloud CLI.

    • On Linux, download the corresponding file.

      curl -O https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-cli-linux-x86_64.tar.gz
      
* Extract the contents of the file.
Enter fullscreen mode Exit fullscreen mode
    ```
    tar -xf google-cloud-cli-linux-x86_64.tar.gz
    ```
Enter fullscreen mode Exit fullscreen mode
* Run the installation script.
Enter fullscreen mode Exit fullscreen mode
    ```
    ./google-cloud-sdk/install.sh
    ```
Enter fullscreen mode Exit fullscreen mode
  1. Update your gcloud CLI installation to get the latest features.

    gcloud components update
    

Backup your database

  1. Create a directory to store the backup and credentials.

    mkdir local-firestore
    cd local-firestore
    
  2. Install firestore-backfire.

    npm install -g firestore-backfire
    
  3. Get Service Account credentials.

    • Go to the Firebase Console → Project Settings → Service Accounts.
    • Click Generate new private key and download the JSON file and rename it as credentials.json.
    • Copy the file to the directory created above.
  4. Export all documents from specific collections to a local .ndjson file.

    backfire export ./data.ndjson \
      -P your-project-id \
      -K ./credentials.json \
      --paths users products
    

    The name assigned to the backup of your database is data.ndjson.

    Where your-project-id is the ID of your project that you can get from the Firebase console.

    The Service Account credentails are in the credentials.json file downloaded before.

    users and products are the collections being backed up. Replace with the collections in your database.

Run the emulator

Run the emulator with the following command.

gcloud emulators firestore start --host-port=127.0.0.1:8304
Enter fullscreen mode Exit fullscreen mode

Restore your database

To restore your database from the data.ndjson file, run the following command.

backfire import ./data.ndjson \
  -E 127.0.0.1:8304 \
  --mode overwrite \
  -P your-project-id
Enter fullscreen mode Exit fullscreen mode

Update your app

I have a .env.local file with the following variables set.

VITE_FIREBASE_API_KEY=""
VITE_FIREBASE_AUTH_DOMAIN=""
VITE_FIREBASE_PROJECT_ID=""
VITE_FIREBASE_STORAGE_BUCKET=""
VITE_FIREBASE_MESSAGING_SENDER_ID=""
VITE_FIREBASE_APP_ID=""
Enter fullscreen mode Exit fullscreen mode

I added the following ones:

VITE_USE_EMULATOR=true
VITE_FIRESTORE_EMULATOR_HOST=127.0.0.1
VITE_FIRESTORE_EMULATOR_PORT=8304
Enter fullscreen mode Exit fullscreen mode

On the firebase.ts file, import connectFirestoreEmulator from firebase/firestore.

import {
  getFirestore,
  Firestore,
  collection,
  doc,
  getDoc,
  setDoc,
  updateDoc,
  deleteDoc,
  query,
  where,
  getDocs,
  onSnapshot,
  writeBatch,
  connectFirestoreEmulator
} from 'firebase/firestore';
Enter fullscreen mode Exit fullscreen mode

After these lines:

    app = initializeApp(firebaseConfig);
    auth = getAuth(app);
    db = getFirestore(app);
Enter fullscreen mode Exit fullscreen mode

I added the following lines to validate when the project is running locally.

    if (import.meta.env.VITE_USE_EMULATOR === 'true') {
      const EMULATOR_HOST = import.meta.env.VITE_FIRESTORE_EMULATOR_HOST || "127.0.0.1";
      const EMULATOR_PORT = Number(import.meta.env.VITE_FIRESTORE_EMULATOR_PORT) || 8304;

      connectFirestoreEmulator(db, EMULATOR_HOST, EMULATOR_PORT);
      console.log(`Firebase.ts: Connected to Firestore Emulator at http://${EMULATOR_HOST}:${EMULATOR_PORT}`);
    }
Enter fullscreen mode Exit fullscreen mode

Now when the app is run locally, it will connect to the Firestore emulator.

Top comments (0)