A Studio that physically cannot mutate prod, error messages that never leak PII, one dependency (pg, no WASM engine), and SQL-first migrations with checksum drift detection. Underneath it's Postgres-maximalist — typed pgvector, RLS sessions, and realtime are all first-class. The rest is below.
Postgres-native
KNN ranking and distance filters over vector columns — orderBy: { embedding: { distance: { to, metric: "cosine" } } }. l2 / cosine / inner-product, every value bound as a parameter.
Vector docs →Postgres pub/sub with db.$listen(channel, handler) and db.$notify(channel, payload). No broker, no extra service — your database is the message bus.
Realtime docs →Multi-tenant isolation the database enforces. $transaction(fn, { sessionContext }) sets transaction-local GUCs so Row-Level Security policies filter rows for you.
Transactions docs →where: { body: { search: 'postgres & orm' } } compiles to to_tsvector @@ to_tsquery with the query bound as a parameter. Pick any text search config. No extension, no extra service.
Operator docs →Pure junction tables are detected at generate time — db.posts.findMany({ with: { tags: true } }) just works. Self-relations too: a self-referencing FK gives you parent + children.
Relations docs →db.$on("query") taps every query with PII-redacted params. db.$observe() flushes p50/p95/p99 aggregates to Postgres, and npx turbine observe is the dashboard. No agent, no SaaS.
Observability docs →What Prisma and Drizzle don't ship
Turbine ships pg and nothing else. No WASM engine (Prisma: 1.6 MB), no adapter chain, no lockstep package upgrades. The main entry bundles to ~31 KB brotli, ~22 KB on the edge.
npx turbine studio launches a loopback-bound web UI. Every query runs inside BEGIN READ ONLY. 192-bit auth token, no raw-SQL surface at all, X-Frame-Options: DENY. No other TS ORM ships this.
Turbine errors show WHERE keys, not values. A UniqueConstraintError says which column violated the constraint — never the actual user data. Safe to log, safe to surface to monitoring, no scrubbing needed.
Write real SQL. SHA-256 checksums catch modified migrations. pg_try_advisory_lock() prevents concurrent runs. Each migration in its own transaction. No magic DSL between you and your database.
turbineHttp(pool, SCHEMA) — same API on Neon, Vercel Postgres, Cloudflare Hyperdrive, Supabase. No WASM bundle to ship, no adapter package to install, no separate serverless build step.
Real Parse/Bind/Execute pipeline — not queries wrapped in a transaction. N independent queries in one round-trip. Deep with clauses compile to one SQL statement using json_agg.
How it works
Every ORM claims single-query nested loads now. Turbine uses the same json_agg approach as Prisma 7 and Drizzle v2. The difference isn't the query strategy — it's everything around it: the one-dependency, no-WASM footprint, the read-only Studio, and the error messages that never expose user data.
SELECT "users".*,
(SELECT COALESCE(json_agg(json_build_object(
'id', t0."id",
'title', t0."title",
'comments', (SELECT COALESCE(json_agg(json_build_object(
'id', t1."id",
'body', t1."body"
)), '[]'::json) FROM "comments" t1
WHERE t1."post_id" = t0."id")
)), '[]'::json)
FROM (SELECT * FROM "posts"
WHERE "posts"."user_id" = "users"."id"
ORDER BY "posts"."created_at" DESC
LIMIT 5) t0
) AS "posts"
FROM "users"
WHERE "users"."org_id" = $1Comparison
One install, one generate, one query. Get a typed Postgres client in under two minutes.