firebase-firestore
npx machina-cli add skill JanSzewczyk/claude-plugins/firebase-firestore --openclawFirebase Firestore Skill
Create production-ready Firestore database queries with TypeScript, proper type lifecycle, structured error handling, and best practices.
Quick Reference
| Document | Purpose |
|---|---|
| types.md | Type utilities and lifecycle patterns |
| errors.md | DbError class and error categorization |
| config.md | Firebase Admin SDK configuration |
| examples.md | Complete CRUD operation examples |
| patterns.md | Best practices and anti-patterns |
| seeding.md | Database seeding patterns |
Instructions
Before Implementation
- Read project context at
.claude/project-context.mdfor project-specific patterns - Check existing patterns in
lib/firebase/for configuration - Review feature structure in
features/*/server/db/for query patterns
Workflow
- Define types using the type lifecycle pattern (Base → Firestore → Application → DTOs)
- Create transform function to convert Firestore data to application types
- Implement queries with tuple return pattern
[DbError | null, Data | null] - Add error handling using
DbErrorclass andcategorizeDbError - Include logging with structured context at all error points
- Test edge cases (empty inputs, not found, permissions)
File Organization
features/
└── [feature]/
├── types/
│ └── [resource].ts # Type definitions
└── server/
└── db/
├── [resource]-queries.ts # CRUD operations
└── seed-[resource].ts # Seeding (if needed)
Core Concepts
Type Lifecycle
Firebase requires different type representations at different stages:
// 1. Base type - Business fields only
type ResourceBase = {
name: string;
status: "active" | "inactive";
};
// 2. Firestore type - With Timestamp objects
type ResourceFirestore = WithFirestoreTimestamps<ResourceBase>;
// 3. Application type - With id and Date objects
type Resource = WithDates<ResourceBase>;
// 4. Create DTO - For creating documents
type CreateResourceDto = CreateDto<ResourceBase>;
// 5. Update DTO - For updating documents
type UpdateResourceDto = UpdateDto<ResourceBase>;
See types.md for complete type utilities.
Error Handling Pattern
All database queries return tuples for explicit error handling:
export async function getResourceById(
id: string,
): Promise<[null, Resource] | [DbError, null]> {
// Input validation
if (!id?.trim()) {
return [DbError.validation("Invalid id provided"), null];
}
try {
const doc = await db.collection(COLLECTION).doc(id).get();
if (!doc.exists) {
return [DbError.notFound(RESOURCE_NAME), null];
}
return [null, transformToResource(doc.id, doc.data()!)];
} catch (error) {
return [categorizeDbError(error, RESOURCE_NAME), null];
}
}
See errors.md for complete error handling.
Transform Functions
Convert Firestore documents to application types:
function transformToResource(
docId: string,
data: FirebaseFirestore.DocumentData,
): Resource {
return {
id: docId,
...data,
// Convert Timestamp to Date
createdAt: data.createdAt?.toDate(),
updatedAt: data.updatedAt?.toDate(),
} as Resource;
}
Questions to Ask
Before implementing database queries, clarify:
- What is the resource name? (e.g., "Budget", "User", "Category")
- What fields does the resource have? (business fields only)
- Are there custom Date fields? (beyond createdAt/updatedAt)
- What queries are needed? (getById, getAll, getByUserId, etc.)
- Is seeding required? (predefined data)
- What are the access patterns? (by user, by status, etc.)
Usage Examples
Basic Query Function
import "server-only";
import { db } from "~/lib/firebase";
import { categorizeDbError, DbError } from "~/lib/firebase/errors";
import { createLogger } from "~/lib/logger";
import type { Budget } from "../types/budget";
const logger = createLogger({ module: "budget-db" });
const COLLECTION = "budgets";
const RESOURCE = "Budget";
export async function getBudgetById(
id: string,
): Promise<[null, Budget] | [DbError, null]> {
if (!id?.trim()) {
const error = DbError.validation("Invalid budget id");
logger.warn({ errorCode: error.code }, "Validation failed");
return [error, null];
}
try {
const doc = await db.collection(COLLECTION).doc(id).get();
if (!doc.exists) {
logger.warn({ budgetId: id }, "Budget not found");
return [DbError.notFound(RESOURCE), null];
}
logger.info({ budgetId: id }, "Budget retrieved");
return [null, transformToBudget(doc.id, doc.data()!)];
} catch (error) {
const dbError = categorizeDbError(error, RESOURCE);
logger.error({ budgetId: id, errorCode: dbError.code }, "Query failed");
return [dbError, null];
}
}
Usage in Server Actions
export async function updateBudget(
budgetId: string,
data: UpdateBudgetDto,
): ActionResponse<Budget> {
const { userId } = await auth();
if (!userId) {
return { success: false, error: "Unauthorized" };
}
const [error, budget] = await updateBudgetInDb(budgetId, data);
if (error) {
if (error.isNotFound) {
return { success: false, error: "Budget not found" };
}
return { success: false, error: error.message };
}
revalidatePath("/budgets");
return { success: true, data: budget };
}
Usage in Page Loaders
async function loadBudget(budgetId: string) {
const { userId } = await auth();
if (!userId) redirect("/sign-in");
const [error, budget] = await getBudgetById(budgetId);
if (error) {
if (error.isNotFound) notFound();
if (error.isRetryable) throw error; // Let error.tsx handle
throw new Error("Unable to load budget");
}
return budget;
}
Related Documentation
- types.md - Complete type utilities
- errors.md - Error handling patterns
- config.md - Firebase configuration
- examples.md - Full CRUD examples
- patterns.md - Best practices
- seeding.md - Seeding patterns
Related Skills
server-actions- For implementing server actions that use these queriesdb-migration- For migrating Firestore data
Source
git clone https://github.com/JanSzewczyk/claude-plugins/blob/main/plugins/firebase-auth/skills/firebase-firestore/SKILL.mdView on GitHub Overview
Build production-ready Firestore queries with TypeScript, enforcing a type lifecycle from base types to DTOs. This approach delivers robust error handling, structured logging, and server-safe patterns for Next.js apps.
How This Skill Works
Define a Type Lifecycle: Base → Firestore → Application → DTOs. Create a transform function to map Firestore data to your app types, and implement queries that return a [DbError|null, Data|null] tuple. Use DbError and categorizeDbError for error handling, and log context at every error point.
When to Use It
- Building read/write queries for user profiles in Next.js API routes
- Implementing CRUD operations for budget management
- Adding robust error handling to Firestore queries
- Seeding Firestore with predefined data
- Enforcing server-only data access patterns with proper types
Quick Start
- Step 1: Define the Type Lifecycle (Base → Firestore → Application → DTOs) for your resource
- Step 2: Implement transformToResource and CRUD queries that return [DbError|null, Data|null]
- Step 3: Use categorizeDbError and structured logging; test edge cases (empty input, not found, permissions)
Best Practices
- Apply the Type Lifecycle by transitioning from Base to Firestore to Application types and then to DTOs
- Return [DbError|null, Data|null] tuples for all queries and handle with categorizeDbError
- Validate inputs early and handle not-found and permission errors explicitly
- Use a dedicated transformToResource function to map Firestore docs to application types
- Log structured context at every error point to aid debugging and monitoring
Example Use Cases
- Create database queries for user profiles
- Implement CRUD operations for budget management
- Add error handling to Firestore queries
- Set up Firebase seeding for predefined data
- Transform Firestore documents into application types using transformToResource
Frequently Asked Questions
Related Skills
postgresql
chaterm/terminal-skills
PostgreSQL 数据库管理
mysql
chaterm/terminal-skills
MySQL 数据库管理与运维
sql-optimization
chaterm/terminal-skills
SQL 优化与调优
redis
chaterm/terminal-skills
Redis 数据库管理
mongodb
chaterm/terminal-skills
MongoDB 数据库管理
Database Design Expert
martinholovsky/claude-skills-generator
Expert in database schema design with focus on normalization, indexing strategies, FTS optimization, and performance-oriented architecture for desktop applications