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.
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?
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