Chapter 01 · Firestore Foundations, Firebase/Google Cloud, Editions, Modes, Locations, and Lab Setup

Create a Database, Configure SDKs / CLI, Use Emulator Suite Where Appropriate, and Verify Reads / Writes

Create and configure a Firestore learning environment with pinned Firebase CLI, Web/Admin SDKs, Emulator Suite, restrictive Security Rules, deterministic data, and observable client/server read-write paths.

Beginner → Advanced110–130 minutesHands-on SDK/CLI lessonNode.js 22+ · CLI 15.30.0 · Web 12.19.0 · Admin 14.4.0Last reviewed: September 2026

Learning outcomes

The first useful Firestore environment is one you can destroy and rebuild. AtlasMart will configure a demo project, start Auth and Firestore emulators, seed deterministic documents through a trusted server path, and prove that an untrusted client is constrained by Security Rules.

01

Pin and verify the Firebase CLI, Web SDK, Admin SDK and Node runtime used by the lab.

02

Configure Firestore/Auth emulators with explicit project ID, ports, Rules and index definitions.

03

Initialize a Web SDK client and Admin SDK server process against the emulator without production credentials.

04

Prove successful and denied client operations and contrast them with the trusted Admin path.

05

Diagnose common wrong-environment failures such as accidental production endpoints, wrong project IDs and permissive Rules.

Chapter baseline reviewed 13 September 2026

The reproducible lab pins Firebase CLI 15.30.0, Firebase JavaScript SDK 12.19.0, Firebase Admin Node.js SDK 14.4.0, and Node.js 22 or newer for the Admin SDK. These are a dated lab baseline, not permanent course guarantees. Firestore service capabilities, editions, pricing, locations, emulator fidelity and SDK support continue to evolve; re-check the official documentation before using the commands later.

Execution and safety note

The generation environment used to build this chapter does not run Firebase Emulator Suite or a billed Google Cloud project. Commands and API shapes were checked against current official documentation, but expected output is described by invariant and evidence shape rather than fabricated as captured output. The mandatory lab uses a Firebase demo project ID and local emulators. Optional production verification must use an isolated test project with explicit billing awareness.

1. Reproducibility begins before `firebase init`

A tutorial that says “install Firebase and run the emulator” has already hidden version and environment assumptions. Chapter 01 records the exact runtime and packages first. As of this review, Firebase Admin Node.js 14.x requires Node.js 22 or higher. The course pins Firebase CLI 15.30.0, Firebase Web SDK 12.19.0 and Firebase Admin Node.js 14.4.0.

Pinning does not claim those versions will remain current. It creates a reproducible baseline. When a later learner updates the versions, the diff is deliberate and the release notes can be reviewed.

shell / PowerShell · record tool identity
node --versionnpm --versionmkdir atlasmart-firestore-labcd atlasmart-firestore-labnpm init -y# Replace package.json with the pinned file below, then:npm installnpx firebase --version
package.json · pinned dependencies
{  "name": "atlasmart-firestore-lab",  "private": true,  "type": "module",  "engines": { "node": ">=22" },  "dependencies": {    "firebase": "12.19.0",    "firebase-admin": "14.4.0"  },  "devDependencies": {    "firebase-tools": "15.30.0"  },  "scripts": {    "emulators": "firebase emulators:start --project demo-atlasmart-firestore --only auth,firestore",    "seed": "node scripts/seed.mjs",    "client-check": "node scripts/client-check.mjs",    "server-check": "node scripts/server-check.mjs"  }}

2. Use a demo project ID for the mandatory lab

Firebase Emulator Suite supports demo project IDs that begin with demo-. The advantage is safety: the ID has no live Google Cloud project backing it, so an accidental request to a non-emulated production service cannot silently bill or mutate a cloud database under that demo ID.

Set the same project ID everywhere—Firebase CLI, Web SDK config, Admin SDK project ID and environment variables. Inconsistent IDs create subtle failures where Auth tokens, Rules evaluation and Firestore data appear to belong to different projects.

firebase.json · explicit services and ports
{  "firestore": {    "rules": "firestore.rules",    "indexes": "firestore.indexes.json"  },  "emulators": {    "auth": { "port": 9099 },    "firestore": { "port": 8080 },    "ui": { "enabled": true, "port": 4000 },    "singleProjectMode": true  }}

3. Start from restrictive Security Rules

The first Rules file should express the trust model, not just make the sample pass. AtlasMart exposes product reads publicly for this synthetic lab, blocks all client product writes, and lets an authenticated user read/write only their own profile. A final recursive rule denies everything else.

firestore.rules · explicit allow list
rules_version = '2';service cloud.firestore {  match /databases/{database}/documents {    match /products/{productId} {      allow read: if true;      allow write: if false;    }    match /profiles/{uid} {      allow read, create, update:        if request.auth != null && request.auth.uid == uid;      allow delete: if false;    }    match /{document=**} {      allow read, write: if false;    }  }}
firestore.indexes.json · no Chapter 01 composite indexes
{  "indexes": [],  "fieldOverrides": []}

This is intentionally simple enough to audit visually. Later chapters introduce query-compatible Rules, field validation, access-call limits and CI rule tests.

4. Start emulators and inspect the endpoints you actually reached

emulator lifecycle · start or run one bounded command
npm run emulators# In another terminal:npx firebase emulators:exec \  --project demo-atlasmart-firestore \  --only auth,firestore \  "node -e \"console.log('emulator command boundary works')\""

Expected evidence includes the project ID and the configured ports. The Emulator UI should be reachable locally on port 4000. Firestore and Auth service logs should identify local endpoints. A green UI proves the local processes are running; it does not prove production quotas, latency, indexing, IAM or region.

5. Seed through the trusted server path

The Admin SDK is appropriate for deterministic seed/reset work because this path represents a trusted backend. Against the emulator it requires no downloaded production service-account key. The environment variables route Admin Firestore to the emulator and make the project identity explicit.

scripts/seed.mjs · trusted deterministic seed
process.env.FIRESTORE_EMULATOR_HOST = "127.0.0.1:8080";process.env.GCLOUD_PROJECT = "demo-atlasmart-firestore";import { initializeApp } from "firebase-admin/app";import { getFirestore } from "firebase-admin/firestore";initializeApp({ projectId: "demo-atlasmart-firestore" });const db = getFirestore();await db.doc("products/p-1001").set({  name: "Trail Camera",  category: "cameras",  price: 129.90,  public: true,  schemaVersion: 1});await db.doc("products/p-1002").set({  name: "USB-C Hub",  category: "accessories",  price: 49.50,  public: true,  schemaVersion: 1});console.log("seeded AtlasMart emulator documents");process.exit(0);

Run npm run seed only after the emulator starts. Verify the two product documents in the Emulator UI and via a client read. Their presence proves the Admin path wrote to the local emulator; it does not prove the equivalent production IAM role is safe.

6. Prove client allow and deny behavior

The Web SDK script signs in anonymously against the Auth emulator, reads a public product, writes the authenticated user's own profile, and deliberately attempts a forbidden product write. The failure is part of the lesson: authorization is observable only when both allow and deny cases are tested.

scripts/client-check.mjs · untrusted client path
process.env.FIREBASE_AUTH_EMULATOR_HOST = "127.0.0.1:9099";process.env.FIRESTORE_EMULATOR_HOST = "127.0.0.1:8080";import { initializeApp } from "firebase/app";import {  getFirestore, connectFirestoreEmulator, doc, getDoc, setDoc} from "firebase/firestore";import {  getAuth, connectAuthEmulator, signInAnonymously} from "firebase/auth";const app = initializeApp({  apiKey: "demo-key",  projectId: "demo-atlasmart-firestore",  appId: "1:123:web:demo"});const db = getFirestore(app);const auth = getAuth(app);connectFirestoreEmulator(db, "127.0.0.1", 8080);connectAuthEmulator(auth, "http://127.0.0.1:9099", { disableWarnings: true });const credential = await signInAnonymously(auth);const uid = credential.user.uid;const product = await getDoc(doc(db, "products", "p-1001"));console.log("public product readable:", product.exists(), product.data()?.name);await setDoc(doc(db, "profiles", uid), {  displayName: "AtlasMart learner",  schemaVersion: 1});console.log("own profile write allowed:", uid);try {  await setDoc(doc(db, "products", "p-client-write"), { name: "forbidden" });  throw new Error("unexpected client product write success");} catch (error) {  console.log("client product write denied as intended:", error.code ?? error.message);}

Expected evidence: the public product exists, the user's own profile write succeeds, and the product write is rejected with a Firestore permission error. If the forbidden write succeeds, stop the lesson and inspect project ID, emulator routing and Rules before continuing.

7. Prove that trusted server access follows a different path

Now write a product through the Admin SDK. The Rules file explicitly denies client product writes, but the Admin/server path is privileged and does not use Firestore Security Rules. This is the boundary future backend services must respect.

scripts/server-check.mjs · trusted server path
process.env.FIRESTORE_EMULATOR_HOST = "127.0.0.1:8080";process.env.GCLOUD_PROJECT = "demo-atlasmart-firestore";import { initializeApp } from "firebase-admin/app";import { getFirestore } from "firebase-admin/firestore";initializeApp({ projectId: "demo-atlasmart-firestore" });const db = getFirestore();await db.doc("products/p-server-write").set({  name: "Trusted backend fixture",  category: "lab",  price: 1,  schemaVersion: 1});const snap = await db.doc("products/p-server-write").get();console.log("trusted server write/read:", snap.exists, snap.data()?.name);

The successful Admin write is not a Rules bypass vulnerability; it is the defined server authorization model. In production, that privilege must be constrained with IAM and application-layer authorization. Never ship Admin credentials or server client libraries into a browser bundle.

8. Troubleshooting matrix: identify the state surface first

Most first-day Firestore problems are environment-identity problems, not database-engine problems. Before changing code, print the project ID and inspect emulator environment variables.

Symptom Likely cause Evidence/fix
Client reads production unexpectedly Emulator connection missing or executed too late Call connectFirestoreEmulator before reads; inspect logs/project ID
PERMISSION_DENIED on client Rules intentionally deny or auth state missing Check Auth emulator user and Rules path
Admin write succeeds despite deny rule Expected server behavior Remember Admin/server bypass Rules; verify IAM in production
Client sees no seed data Project/database mismatch or seed hit another endpoint Compare project IDs and FIRESTORE_EMULATOR_HOST
Compound query works locally but production wants index Known emulator difference Test index requirements in isolated production verification

9. Cleanup is part of the lab contract

Stop the emulator with the terminal interrupt. Because the default emulator state is in memory unless you explicitly import/export, restarting starts clean. If you use export files later, put them under a course-specific directory and delete only that directory.

cleanup/reset · local resources only
# Stop the running emulator process with Ctrl+C.# Optional deterministic export/import workflow for later chapters:mkdir -p .emulator-datanpx firebase emulators:start \  --project demo-atlasmart-firestore \  --only auth,firestore \  --import=.emulator-data \  --export-on-exit=.emulator-data# Never run recursive cleanup against an unrelated real project.

10. Production bridge

At this point AtlasMart has evidence for SDK initialization, local Firestore/Auth endpoints, Rules allow/deny behavior and the server/client trust split. It still has no evidence for production location, pricing, SLA, cloud IAM, index enforcement or Enterprise Pipeline behavior. That separation is intentional.

Lesson 5 turns these pieces into a repeatable course harness with setup, seed, verification, logging and safe reset expectations that later chapters can reuse unchanged.

Knowledge check

Check your understanding

  1. Why does the mandatory lab use a `demo-` project ID?
  2. Why should the Admin SDK be able to write a product that client Security Rules deny?
  3. What evidence indicates a client accidentally connected to production instead of the emulator?
  4. Why is a successful compound query in the emulator not proof that production indexing is correct?
  5. What should happen if the deliberately forbidden client product write succeeds?
Review the answers

1. A demo project ID is not backed by live Google Cloud resources. It reduces the chance that an accidental non-emulated call mutates or bills a production project.

2. Admin/server libraries use a privileged IAM/ADC path and bypass Firestore Security Rules. That is expected; production server authorization must be controlled separately.

3. The Firestore emulator log/UI would not show the request, emulator environment/connection may be missing, and production credentials/network traffic may appear. The code should print/record project and endpoint identity before writes.

4. The emulator currently does not enforce compound indexes the same way production does. Index-dependent queries need a production verification layer or explicit index configuration tests later.

5. Stop. The lab's security invariant is broken. Check that the SDK connected to the intended emulator/project, that the Rules file loaded, and that no permissive catch-all rule exists.

Summary and next step

Chapter 01 keeps Firestore claims tied to an observable state surface: client versus server, emulator versus production, project versus database, and Standard versus Enterprise/mode. Preserve the lab evidence and do not convert unknown production facts into assumptions.

Next, continue to Build a Reproducible Lab with Authentication, Rules, Test Data, Index Configuration, Logging, and Safe Cleanup.

Authoritative references

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only Ethereum or ERC-20 compatible assets to this address.