node.jsfirebasegoogle-cloud-firestorefirebase-admin

Where does Firebase Admin SDK / Firestore pick up its project ID from, if not specified?


I'm trying to debug why writes to the local Firestore emulator from a Node.js script on my laptop aren't visible in the emulator GUI, and why the Node.js script gets different data from what I see in the GUI. In other words, it seems the Node.js script is simply accessing a different Firestore instance locally (it works with the Internet off), perhaps partitioned by the emulator for a different project ID.

The emulator is run with firebase emulators:start --only functions,firestore and at http://127.0.0.1:4000/firestore/default/data/ I see data added by emulated functions. The home page confirms the project ID, which is clearly not used by the Node.js script.

Firebase emulator

Below is my initialization code:

import { initializeApp } from 'firebase-admin/app';
import { getFirestore } from 'firebase-admin/firestore';

for (const envVar of [
  'FIREBASE_CONFIG',  // env var listed at https://firebase.google.com/docs/admin/setup#initialize-sdk
  'GOOGLE_APPLICATION_CREDENTIALS',  // env var listed at https://firebase.google.com/docs/admin/setup#initialize_the_sdk_in_non-google_environments
  'GOOGLE_CLOUD_PROJECT', 'GCLOUD_PROJECT'  // observed access while debugging with Deno
])
  console.log(`${envVar}:`, process.env[envVar]);  // all undefined

// Connect to the emulator per https://firebase.google.com/docs/emulator-suite/connect_firestore#admin_sdks or https://cloud.google.com/firestore/docs/emulator#server_client_libraries
process.env['FIRESTORE_EMULATOR_HOST'] = '127.0.0.1:8080';
// Initialize Cloud Firestore per https://firebase.google.com/docs/firestore/quickstart#initialize -> Node.js -> Initialize on your own server
initializeApp();
const db = getFirestore();

That's it. No parameters are passed to initializeApp(), and I've run the script with Deno to see what env vars it wants. The only relevant ones are above (out of quite a ton, plus launching /bin/sh, but that's a different issue). It also doesn't attempt to read .firebaserc, or firebase.json.

So how does Firebase/Firestore determine what project ID to use in this case?


Solution

  • When using Firestore, the Firebase Admin SDK just wraps the Google Cloud Firestore SDK. It exposes the exact same functionality and API.

    The GCP product SDKs use a common library to find the project ID. You can see the source code here: https://github.com/googleapis/google-auth-library-nodejs/blob/main/src/auth/googleauth.ts

      /**
       * Obtains the default project ID for the application.
       *
       * Retrieves in the following order of precedence:
       * - The `projectId` provided in this object's construction
       * - GCLOUD_PROJECT or GOOGLE_CLOUD_PROJECT environment variable
       * - GOOGLE_APPLICATION_CREDENTIALS JSON file
       * - Cloud SDK: `gcloud config config-helper --format json`
       * - GCE project ID from metadata server
       */
    

    If you're not explicitly providing an environment variable or running within a GCP product, then it's likely that it's using output from gcloud to find a default project ID.

    gcloud config config-helper --format json