DEV Community

HBFL3Xx
HBFL3Xx

Posted on

I Built a Firestore ORM Because Raw Firebase Queries Were Killing My Productivity

Honestly, I hit a wall. After spending years building backends with Firestore, I was spending more time writing boilerplate than actually shipping features. Every collection meant writing the same CRUD patterns again, managing soft deletes manually, dealing with validation scattered everywhere, and constantly running into composite index errors at 2 AM.
I looked for solutions, but the existing Firestore ORMs either felt abandoned or were too opinionated for real-world work. So I built FirestoreORM—basically the tool I wish existed when I started.

What's Different Here
The core philosophy is: get out of your way when you need to move fast, but catch mistakes before they hit production.
Type-safe by default. Everything's fully typed with TypeScript inference. No more guessing what fields exist or what type a query returns.

Validation that actually works. Drop a Zod schema in, and it automatically validates every create and update before it touches Firestore. Invalid data gets caught instantly with clear error messages.

Soft deletes built-in. Your data isn't actually gone—just marked as deleted. Recovery is one method call away. Queries automatically exclude deleted docs unless you ask otherwise. Audit trails, accidental deletion recovery, compliance—it's all there.

Lifecycle hooks that feel natural. Need to send an email after someone signs up? Log changes for auditing? Run cleanup on deletion? Just hook into beforeCreate, afterCreate, etc. No messy callback hell.

Query builder that doesn't suck. Filtering, sorting, pagination, aggregations—all chainable and intuitive. Cursor-based pagination by default (way cheaper than offset pagination on large datasets).

Transactions done right. Critical operations like money transfers or inventory updates just work atomically. The ORM handles the complexity.

Real Code, Real Speed

// Set up once
const userRepo = FirestoreRepository.withSchema<User>(
  db,
  'users',
  userSchema
);

// Create (auto-validated)
const user = await userRepo.create({
  name: 'Alice',
  email: 'alice@example.com'
});

// Query (fully typed)
const activeUsers = await userRepo.query()
  .where('status', '==', 'active')
  .where('age', '>', 18)
  .orderBy('createdAt', 'desc')
  .paginate(20);

// Soft delete (recoverable)
await userRepo.softDelete(user.id);
await userRepo.restore(user.id); // instant recovery
Enter fullscreen mode Exit fullscreen mode

No ceremony. Just readable, fast code.

Framework Agnostic
Whether you're in Express, NestJS, Fastify, Next.js, or just a plain Node.js script, it works. No vendor lock-in—it's all built on the Firebase Admin SDK you're already using.

What You Get

  • Full TypeScript support with intelligent type inference
  • Zod schema validation baked in
  • Soft deletes that actually save time
  • Lifecycle hooks for clean side effects
  • Query builder with pagination, aggregation, streaming
  • Transaction support for critical operations
  • Subcollection support
  • Real-time listeners with onSnapshot
  • Built-in error handling

Check it out: github.com/HBFLEX/spacelabs-firestoreorm
https://www.npmjs.com/package/@spacelabstech/firestoreorm

Installation is a one-liner:

npm install @spacelabstech/firestoreorm firebase-admin zod
Enter fullscreen mode Exit fullscreen mode

The docs have everything—real-world examples with e-commerce orders, multi-tenant apps, social feeds, performance cost breakdowns, best practices. I spent a lot of time on this because I wanted to ship something actually useful, not just another half-baked library.

This is my first open-source library project, so I'm genuinely interested in feedback. If you've dealt with Firestore pain, try it out and let me know what you think. Issues, suggestions, contributions—all welcome.

Happy coding.

Top comments (0)