| name | firebase-firestore |
| description | Firestore database layer for Next.js. Use when user asks to "Firestore query", "Firebase Admin SDK", "CRUD for Firestore", "seed Firestore", FieldValue.serverTimestamp(), Firestore transactions, "db collection query", "implement database queries", "Firestore error handling", "ServiceError for Firestore". Implements the ServiceError contract defined in the error-handling skill.
|
| allowed-tools | Read, Write, Edit, Glob, Grep, Bash, mcp__context7__* |
Firebase Firestore Skill
Production-ready Firestore queries with TypeScript, a proper type lifecycle, structured error handling,
and the tuple return pattern. This file holds the rules; detailed code lives in the references.
Workflow
- Define types with the lifecycle pattern (Base → Firestore → Application → DTOs).
- Write a transform that converts a Firestore document to the application type (Timestamp → Date).
- Implement queries returning the tuple
[ServiceError | null, Data | null].
- Handle errors via
ServiceError + categorizeServiceError(), logging structured context at every
error point.
- Cover edge cases — empty input, not found, permission denied.
Place queries in features/[feature]/server/db/[resource]-queries.ts; types in
features/[feature]/types/[resource].ts.
Type Lifecycle
Firestore needs different representations at different stages (full utilities in
types.md):
type ResourceBase = { name: string; status: "active" | "inactive" };
type ResourceFirestore = WithFirestoreTimestamps<ResourceBase>;
type Resource = WithDates<ResourceBase>;
type CreateResourceDto = CreateDto<ResourceBase>;
type UpdateResourceDto = UpdateDto<ResourceBase>;
Error Handling
Contract: the ServiceError class and categorizeServiceError() here implement the universal
ServiceError contract defined in the error-handling skill. Consumers branch on boolean properties
(isNotFound, isRetryable, isPermissionDenied) without knowing the backend is Firestore.
- Every query returns a tuple —
[ServiceError, null] on failure, [null, data] on success.
Validate input first, wrap the Firestore call in try/catch, run the caught error through
categorizeServiceError(error, resourceName). Worked code in errors.md and
examples.md.
- Consumers branch on the error flags:
- Server Action —
isNotFound → specific message; otherwise return error.message (or a generic).
- Page loader —
isNotFound → notFound(); isRetryable → throw (let error.tsx handle);
otherwise throw a generic error.
Transform Functions
Convert a Firestore document to the application type — spread the data, add id, and turn Timestamps
into Dates:
function transformToResource(docId: string, data: FirebaseFirestore.DocumentData): Resource {
return { id: docId, ...data, createdAt: data.createdAt?.toDate(), updatedAt: data.updatedAt?.toDate() } as Resource;
}
Related Skills
error-handling — defines the ServiceError contract this skill implements.
server-actions — server actions that consume these queries.
db-migration — migrating Firestore data.