v0.19 — read-only Studio with an ORM-native query builder

The Postgres ORM your DBA will sign off on.
Read-only Studio. PII-safe errors. One dependency.

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.

$npm install turbine-orm
query.ts
const docs = await db.documents.findMany({
  where: {
    body: { search: 'vector & index' },
    embedding: { distance: { to: queryVec, metric: 'cosine', lt: 0.4 } },
  },
  orderBy: { embedding: { distance: { to: queryVec, metric: 'cosine' } } },
  with: { author: true },
  limit: 10,
});

// full-text + pgvector KNN + a typed relation
// ^ one Postgres query, fully parameterized

Use the database you actually have.

Built in, not bolted on.

1runtime dep

One dependency. No WASM engine.

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.

0write paths

Read-only Studio your DBA will approve

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.

keysnot values

PII-safe error messages

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.

SHA-256checksums

SQL-first migrations with drift detection

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.

~22 KBedge bundle (brotli)

Edge-native. One import swap.

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.

1round-trip

Pipeline batching via wire protocol

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.

One query. Any depth.

Your code writes one call. Turbine writes one query.

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.

  • Correlated subqueries with json_agg + json_build_object
  • COALESCE ensures empty relations return [] not null
  • Inner subquery wrapping for per-relation LIMIT/ORDER BY
  • Pipeline batching via real Parse/Bind/Execute protocol
  • SQL template caching with FNV-1a shape fingerprinting
Generated SQL
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" = $1

Turbine vs. Prisma vs. Drizzle

TurbinePrismaDrizzle
Engine / runtimeNo engine binary (pg only)Client + 1.6 MB WASM engineNo engine
Runtime deps1 (pg)@prisma/client + adapter0
Main bundle (brotli)~31 KBdominated by 1.6 MB WASM~7 KB core
StudioRead-only, 192-bit authFull CRUD, cloud-hostedDrizzle Studio (paid tier)
Error PII safetyKeys only by defaultValues in messagesRaw pg errors
MigrationsSQL-first, SHA-256 drift detectionDSL-generated, shadow DBSQL or Drizzle Kit
Edge runtimeOne import swap, ~22 KB brotli1.6 MB WASM adapterNative
Pipeline batchingParse/Bind/Execute protocolSequential in txnSequential
Typed errorsisRetryable discriminantError codes onlyNone
Nested relations1 query, deep type inference1 query, shallow inferencerelations() re-declaration
Many-to-manyAuto-detected from junctionsImplicit/explicitExplicit relations()
Vector searchBuilt-in distance / KNNPreview / rawExtension API
LISTEN/NOTIFY$listen / $notifyNoneNone

Start building

One install, one generate, one query. Get a typed Postgres client in under two minutes.