When we started building HBForge, the conventional wisdom was clear: just use Prisma. It has beautiful schema syntax, auto-generated types, a massive community, and investor backing. Every tutorial recommends it. Every boilerplate includes it.
We used it too. For two years, across a dozen production projects. And then we wrote our own ORM from scratch. Here is why.
The 15MB Elephant in the Room
Prisma is not a JavaScript library. It is a Rust binary wrapped in a JavaScript client. When you run npx prisma generate, it downloads a platform-specific query engine binary that weighs in at 15MB or more. On top of that, the generated client adds another 2-4MB of TypeScript definitions and runtime code.
For a traditional server deployment, this is mildly annoying. For serverless? It is a deal-breaker.
AWS Lambda has a 50MB deployment package limit (250MB unzipped). A Prisma-based function, once you add your application code, node_modules, and the query engine, routinely hits 40-60MB. You are burning over half your budget on the ORM alone. And Vercel Edge Functions have a 4MB limit — Prisma cannot even fit.
Cold Starts That Kill User Experience
Every time a serverless function cold-starts, Prisma must:
- Load the Node.js runtime
- Load the JavaScript client wrapper
- Spawn the Rust query engine as a child process
- Wait for the engine to establish a database connection pool
- Finally execute your actual query
On AWS Lambda, this process adds 800ms to 2 seconds to cold starts. We measured it across 50+ production functions. The median cold start with Prisma was 1.4 seconds. Without it? 180ms. The ORM was responsible for 87% of the cold start time.
For API endpoints serving real users, adding a second of latency to every cold start is unacceptable.
The Generated Client Problem
Prisma generates a client tailored to your schema. In theory, this enables type safety. In practice, it creates a fragile build pipeline:
- CI/CD complexity — every build must run
prisma generatebefore TypeScript compilation - Docker layer caching breaks — schema changes invalidate the generated layer, triggering full reinstalls
- Monorepo pain — sharing a Prisma client across packages requires careful hoisting and generation order
- IDE lag — the generated types file can exceed 50,000 lines for large schemas, slowing down TypeScript language server
Raw SQL Is a Second-Class Citizen
Every production application eventually needs raw SQL. Complex reporting queries, recursive CTEs, window functions, database-specific features — the ORM abstraction always leaks. Prisma's $queryRaw exists, but it returns unknown[], forcing you to cast everything manually. There is no way to compose raw SQL with Prisma's query builder. You are either fully in Prisma-land or fully writing raw SQL with no type safety.
What forge/data Does Differently
forge/data is a schema-first ORM written in pure JavaScript. No Rust binary. No code generation step. No child processes. The entire module is 2,800 lines of JavaScript that loads in under 10ms.
Define Your Schema in Code
import { defineSchema, types } from '@hyperbridge/forge/data'; const db = defineSchema({ connection: 'postgresql://localhost:5432/myapp', models: { User: { id: types.uuid().primaryKey(), email: types.string().unique().index(), name: types.string().min(2), role: types.enum('admin', 'user').default('user'), posts: types.hasMany('Post'), createdAt: types.timestamp().default('now'), }, Post: { id: types.uuid().primaryKey(), title: types.string(), body: types.text(), author: types.belongsTo('User'), tags: types.json().default([]), }, }, });
No separate .prisma file. No generation step. The schema is your runtime — change it, and the query builder updates instantly.
Type-Safe Queries Without Code Generation
// Find with relations — fully typed from schema const users = await db.User .where({ role: 'admin' }) .include('posts') .orderBy('createdAt', 'desc') .limit(20) .exec(); // Composable query builder — chain freely const query = db.Post.select('id', 'title'); if (tag) query.whereJsonContains('tags', tag); if (since) query.where('createdAt', '>', since); const results = await query.exec();
Raw SQL as a First-Class Feature
// Raw SQL with automatic parameter binding const report = await db.raw(` SELECT u.name, COUNT(p.id) as post_count FROM users u LEFT JOIN posts p ON p.author_id = u.id WHERE u.created_at > $1 GROUP BY u.id HAVING COUNT(p.id) > $2 ORDER BY post_count DESC `, [startDate, minPosts]); // Mix raw SQL with the query builder const active = await db.User .whereRaw('last_login > NOW() - INTERVAL \'30 days\'') .include('posts') .exec();
Migrations Without a Binary
// Auto-diff schema changes await db.migrate(); // generates & applies SQL diffs // Or generate migration files for review await db.migrate({ dryRun: true }); // → outputs: ALTER TABLE users ADD COLUMN bio TEXT; // Rollback support await db.rollback(); // undo last migration
The Numbers Speak
| Metric | Prisma | forge/data |
|---|---|---|
| Package size | 15MB+ (engine binary) | 48KB (pure JS) |
| Cold start (Lambda) | 1.4s median | 180ms median |
| Edge compatible | No (binary required) | Yes |
| Build step required | prisma generate | None |
| Raw SQL composability | Separate escape hatch | First-class, mixable |
| Dependencies | @prisma/client + engine | Zero |
When to Still Use Prisma
We are not saying Prisma is bad software. If you are building a traditional monolith deployed to a long-running server, the cold start penalty is irrelevant. If your team relies on Prisma Studio for visual database browsing, that is a real productivity tool. If you need multi-database support across MongoDB, MySQL, and PostgreSQL in the same project, Prisma handles that well.
But if you are building serverless-first, deploying to edge runtimes, or simply tired of watching your Lambda deployment package bloat beyond reason — forge/data was built for you. Pure JavaScript. No binaries. No generation step. Your ORM should be a library, not an infrastructure dependency.
HBForge is currently available exclusively for enterprise clients. Opening to the Developer Community on June 25, 2026.
Contact kr@hyperbridge.in for early access.