v0.14 — dialect-owned type metadata

110 KB. One dep.
Production Postgres.

The Postgres ORM that ships light and locks tight. One runtime dependency, a read-only Studio no other ORM has, and error messages that never leak PII. v0.14 routes generated type metadata and bulk-insert array casts through the dialect contract without changing Postgres imports.

$npm install turbine-orm
query.ts
const users = await db.users.findMany({
  where: { orgId: 1 },
  with: {
    posts: {
      with: { comments: true },
      orderBy: { createdAt: 'desc' },
      limit: 5,
    },
  },
});

// users[0].posts[0].comments[0].body
// ^ fully typed, one round-trip

Six things. Zero overlap.

1runtime dep

One dependency. 110 KB.

Turbine ships pg and nothing else. No WASM engine (Prisma: 1.6 MB), no adapter chain, no lockstep package upgrades. 110 KB on npm, 5 KB on the edge entry.

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, statement-stacking guard, 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.

5 KBedge entry

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 110 KB 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
Install size~110 KB (pg only)~1.6 MB (WASM engine)~0 KB (no runtime)
Runtime deps1 (pg)@prisma/client + adapter0
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, 5 KB1.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

Start building

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