Why db-semantic-planner?
The problem
Every major ORM or query builder forces you to make a fundamental trade-off. ORMs like Prisma and TypeORM abstract away SQL to the point where you cannot understand what query will run — until something goes wrong in production. Query builders like Kysely and Drizzle give you back SQL control, but leave you responsible for choosing the right join strategy, preventing N+1 problems, and debugging parameterized query construction. In both cases, the tool's internal decisions are opaque: you see a result, not the reasoning that produced it.
Multi-tenant applications add another layer of complexity. Schema-per-tenant isolation requires manual schema prefixing in every query, across every abstraction layer. Most tools treat this as an afterthought.
How dbsp is different
db-semantic-planner is built around an intent-first paradigm. You declare what data you need — orm.select('users').include('posts').where(eq('active', true)) — and the planner decides how to fetch it. The planner selects the optimal include strategy (json_agg, join, lateral join, or CTE) based on recursion, query shape, and dialect capabilities. By default the planner chooses the strategy, and it explains why.
Every decision is observable. .dump() returns the full plan with reasoning, the compiled SQL, and the bound parameters — before execution. You can inspect what the planner chose and why, log it, or test it without a database connection. This makes debugging deterministic: same inputs always produce the same plan.
Multi-tenant isolation is a first-class primitive. orm.withSchema('tenant_42') returns a new ORM instance where every query, mutation, and DDL operation is automatically scoped to that PostgreSQL schema. No manual prefixing, no middleware boilerplate.
Quick comparison
| Feature | dbsp | Prisma | Drizzle | Kysely |
|---|---|---|---|---|
| Intent-first query planning | Yes | No | No | No |
| Observable decisions (dump) | Full plan + SQL + params | SQL only (preview) | SQL only | SQL only |
| Automatic include strategy | Yes (join / json_agg / lateral / CTE) | Yes (opaque) | Manual | Manual |
| N+1 prevention | Automatic | Yes | Yes | Manual |
| Multi-tenant (withSchema) | Built-in | Manual | Manual | Manual |
| Recursive CTEs | Builder API | No | Manual | Yes |
| Full TypeScript inference | Yes | Yes | Yes | Yes |
| No codegen required | Yes | No | No | Yes |
| pgvector / ParadeDB support | Built-in helpers | Plugin | Plugin | Manual |
| Row-level security (DDL) | Yes | No | No | No |
For the full feature matrix across 16 tools, see the comparison page.