# Firebase

> Use when the project uses Firebase — Firestore, Firebase Auth, Storage, Cloud Functions, Hosting, Realtime Database, Remote Config — including security rules, schemas, Emulators.

- Skill: `muxammadmamajonov/firebase` (Agent Skill)
- Install (CLI): `npx skillmds@latest add muxammadmamajonov/firebase`
- Raw SKILL.md: https://api.skillmd.com/api/skills/muxammadmamajonov/firebase/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: muxammadmamajonov (https://skillmd.com/u/muxammadmamajonov)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/muxammadmamajonov/firebase

---


# Firebase Skill

## When to use

- Architecting Firestore collection/subcollection structure and indexes
- Writing and testing Firestore Security Rules
- Implementing Firebase Auth (email/password, OAuth, custom tokens, custom claims)
- Writing Cloud Functions for Firebase (v1 HTTP, callable, background triggers)
- Configuring Firebase Hosting with rewrite rules to Cloud Functions or Cloud Run
- Setting up the Firebase Emulator Suite for local development and CI
- Diagnosing quota/billing issues, missing indexes, or security-rule denial errors

---

## Workflow

1. **Design the data model before writing code** — Firestore is schemaless but reads are charged per document. Denormalize data intentionally: embed sub-objects that are always read together; use subcollections for unbounded lists.
2. **Initialize the project**: `firebase init` → select Firestore, Functions, Hosting, Emulators. Commit `.firebaserc` and `firebase.json`; gitignore `functions/node_modules`.
3. **Write Security Rules early** — create `firestore.rules` with deny-all as the default, then open exactly what each user role needs. Mirror the same pattern for `storage.rules`.
4. **Test rules with the Emulator** — run `firebase emulators:start` and point the SDK at `localhost:8080` (Firestore) / `localhost:9099` (Auth). Use `@firebase/rules-unit-testing` for automated rule tests.
5. **Add composite indexes via `firestore.indexes.json`** — never create them only in the console; indexes defined in the file are reproducible across environments.
6. **Cloud Functions**: keep each function focused on a single trigger. Use `onCall` for client-invoked logic (handles Auth context automatically). Use `onDocumentWritten`/`onDocumentCreated` for server-side side effects. Avoid chaining background triggers (trigger → function → write → trigger) as this creates infinite loops.
7. **Deploy incrementally**: `firebase deploy --only firestore:rules`, then `--only functions`, then `--only hosting` to limit blast radius.
8. **Before production**: run `firebase firestore:indexes` to confirm indexes are deployed; check the Firebase console → Usage tab for quota headroom.

---

## Standards

### Do
- Use `FieldValue.serverTimestamp()` for `createdAt`/`updatedAt` — never trust client-supplied timestamps.
- Keep Security Rules DRY by extracting helper functions: `function isOwner(uid) { return request.auth.uid == uid; }`.
- Version Cloud Functions explicitly in `package.json` and pin `firebase-admin` and `firebase-functions`.
- Use `admin.auth().verifyIdToken()` in HTTP functions to authenticate callers — never trust a UID passed in the request body.
- Set `region` explicitly on functions deployed to non-`us-central1` regions so client SDKs can connect.
- Use environment config (`firebase functions:config:set`) or Secret Manager (v2 functions) for secrets — never hardcode.

### Do not
- Do not use `allow read, write: if true;` in Security Rules even temporarily in a shared repo.
- Do not store more than ~1 MB of data in a single Firestore document (hard limit is 1 MiB; practical limit is much lower to avoid slow reads).
- Do not use Firestore as a queue — use Cloud Tasks or Pub/Sub for background job delivery.
- Do not run Firestore queries without an equality/range filter on an indexed field; collection-group queries with no filter cause full-collection scans.
- Do not mix client SDK and admin SDK in the same runtime context.
- Do not use `onSnapshot` listeners in Cloud Functions (they run serverless and have no persistent connection).

---

## Common mistakes to avoid

| Mistake | Consequence | Fix |
|---|---|---|
| Missing composite index on a multi-field query | Runtime error thrown to client | Add to `firestore.indexes.json`; deploy before the query goes live |
| Background-trigger infinite loop | Runaway invocations → billing shock | Guard with a state flag: check if the document field already has the expected value before writing |
| Returning sensitive fields in Security Rules `get()` calls | Data exfiltration via rule side-channel | Rules can call `get()` but the fetched data is only visible to the rule engine, not the client — still, limit `get()` usage to avoid extra reads |
| Using `collection.get()` (fetch all docs) in a Cloud Function | Memory exhaustion for large collections | Paginate with `startAfter` or use a Firestore aggregation query |
| Deploying functions without setting a minimum instance count for latency-sensitive paths | Cold-start delays of 2–5 s | Set `minInstances: 1` on functions behind user-facing APIs |
| Not initializing Firebase Admin with `cert()` in non-Google Cloud environments | `GOOGLE_APPLICATION_CREDENTIALS` missing → auth failure | Pass `admin.initializeApp({ credential: admin.credential.cert(serviceAccount) })` |

---

## Output format

```
firebase.json           — hosting rewrites, function config
firestore.rules         — Security Rules
firestore.indexes.json  — composite indexes
storage.rules           — Storage Security Rules
functions/
  src/
    index.ts            — function exports
    auth/               — auth trigger handlers
    http/               — HTTP/callable handlers
    firestore/          — document trigger handlers
  package.json
.firebaserc             — project aliases (default, staging, prod)
```

Cloud Function pattern:
```ts
export const createUserProfile = onCall({ region: "us-central1" }, async (request) => {
  if (!request.auth) throw new HttpsError("unauthenticated", "Login required");
  const uid = request.auth.uid;
  await admin.firestore().doc(`profiles/${uid}`).set({ createdAt: FieldValue.serverTimestamp() });
  return { success: true };
});
```

---

## Related checklists
- `.claude/checklists/security.md`
- `.claude/checklists/database.md`
- `.claude/checklists/launch.md`

## Related agents
- `.claude/agents/engineering/backend-engineer.md`
- `.claude/agents/quality/security-auditor.md`
- `.claude/agents/core/system-analyst.md`

