The TypeScript ORM for Postgres
Raw SQL speed.
Zero raw SQL.
Turbine is the TypeScript ORM that keeps up with Postgres. Your data arrives in one round trip, every field is typed down to the last relation, and the only thing you install is pg.
- faster than Drizzlegeometric mean, see benchmarks
- 1.5x
- round trip for nested datano N+1, no waterfalls
- 1
- the only dependencyno engine, no WASM
- pg
- agent first-try pass ratewith the bundled agent skill
- 97%
Why switch
Stop fighting your ORM.
The things that make database code slow, scary and hard to debug, fixed at the source.
Forty queries to render one page.
Ask for users, their posts and every comment in one call. It all comes back in one round trip, already nested and typed.
One bad filter away from an empty table.
An update or delete with an empty or always-true filter throws instead of running. Doing it on purpose takes a flag no request body can fake.
A slow query nobody can explain.
Print any query before it runs, pull its plan from your code, and let turbine doctor find the index you forgot.
Dependencies you never asked for.
Turbine's entire dependency list is
"pg": "^8.15.0". No engine binary, nothing to keep in sync, and it runs on Node, Vercel Edge, Cloudflare Workers and Deno Deploy.
The API
The API you already know.
The speed you never got.
If you have written Prisma, you can write Turbine today: findMany, where, with, create. The difference is what happens after you hit save.
const feed = await db.users.findMany({
where: { orgId },
with: {
posts: {
orderBy: { createdAt: 'desc' },
limit: 5,
with: { comments: { with: { author: true } } },
},
},
});
feed[0].posts[0].comments[0].author.name; // string, autocompletedA user, their five latest posts and every comment with its author. One round trip, typed to the last field.
const user = await db.users.create({
data: {
email: 'ada@example.com',
name: 'Ada',
posts: {
create: [{ title: 'Hello, Postgres' }, { title: 'Second post' }],
},
},
});A user and their first posts in one call. If any row fails, none of them are written.
await db.$transaction(async (tx) => {
const order = await tx.orders.create({ data: { userId, total } });
await tx.users.update({
where: { id: userId },
data: { credits: { decrement: total } },
});
return order;
});All or nothing. If anything inside throws, none of it happened.
const similar = await db.docs.findMany({
where: { workspaceId },
orderBy: {
embedding: { distance: { to: queryVector, metric: 'cosine' } },
},
limit: 5,
});Nearest-neighbour search on pgvector. Your AI features, without a second database.
for await (const order of db.orders.findManyStream({
where: { status: 'paid' },
orderBy: { id: 'asc' },
})) {
await invoices.send(order);
}Millions of rows in constant memory. Break out early and the cursor closes itself.
Benchmarks
2.1x faster than Prisma.
1.5x faster than Drizzle.
Same schema, same data, same connection pool, real query shapes. Turbine adds 9% to SQL written by hand, Drizzle 59% and Prisma 113%. We publish where we lose, too.
7x faster dashboards
Five dashboard queries sent as one batch, 25 ms from the database: 25 ms instead of 171 ms for a transaction.
Where we lose
Row-by-row streaming. Against Drizzle's 1.0 release candidate our per-row stream takes 52.54 ms to its 46.99. The batched stream ties.
Turbine 0.92.0, October 2026, against Prisma 7.10.0 and Drizzle 0.45.3 on PostgreSQL 17.11, on a dedicated AMD Ryzen 9 7950X benchmark box: 1,000 users, 10,000 posts and 50,000 comments, medians of 3 runs of 200 interleaved rounds. The bars are the geometric mean over the 8 scenarios with a hand-written control; the headline compares 10. The batch figure adds the round trip through a local proxy. Method, raw data and losses on the benchmarks page.
For coding agents
Let your agent drive.
Turbine keeps it on the track.
Turbine ships an agent skill and an MCP server for Claude Code, Cursor and the rest. With the skill installed, agents wrote correct Turbine queries on the first try 97% of the time, up from 73%.
It knows your schema
Every table, every relation, and the path from one to another. No guessing at column names.
It checks before it runs
Your agent can compile a query and read its plan before it ever runs it.
It looks, it never touches
Every tool is read-only, and private columns are redacted before the model sees a single row.
It fixes its own mistakes
Every error code comes with its cause and the fix, so your agent can recover without asking you.
Production-safe
Safe to deploy on a Friday.
Anything that can lose or leak data asks first. Everything else just works.
No accidental wipes
Delete or update with an empty filter and Turbine throws instead of emptying the table. Meant it? There is a flag for that, and a request body cannot set it.
Private columns stay private
Mark a column as PII and it stays out of query results, Studio and your agent until you explicitly ask for it.
Migrations that ask first
Dropping a table or a column waits until you type "destroy my data". In CI you pass a flag, on purpose.
Errors you can ship anywhere
Error messages name the fields, never the values, so they go straight to your error tracker without a scrubbing rule.
A data browser that can’t break things
turbine studio is read-only unless you start it with --write. Try the demo, no database needed.
It finds your missing indexes
turbine doctor spots every relation without an index, ranks them by cost and writes the migration for you.
In the box
Everything you used to drop to raw SQL for.
Typed, documented and free. No paid tier, no account, no telemetry.
- Vector searchSimilarity search on pgvector for your AI features.
- Realtime eventsPush events between servers through Postgres. No Redis.
- Full-text searchReal search over your text columns. No search cluster to run.
- Row-level securityLet Postgres decide who sees which rows.
- Batched queriesSend a whole dashboard of queries in one round trip.
- StreamingWalk millions of rows without running out of memory.
- Soft delete and tenancySet a filter once and every query on the table respects it.
- Query plansAsk Postgres why a query is slow, right from your code.
- MetricsLatency percentiles and a local dashboard. No SaaS.
- Typed errorsEvery error has a code and a link to the fix.
- Many-to-manyJoin tables found and wired up for you.
- More databasesSQLite, MySQL and SQL Server when you need them.
Switching
Move over one file at a time.
No big-bang rewrite. Your old queries keep running while the new ones land.
schema.prisma. A compatibility client keeps most of your existing Prisma code running while you port at your own pace.Prisma migration guide From DrizzleThe Drizzle calls you use, mapped to Turbine, plus the behavior differences to check before you switch.Drizzle migration guide Take the fast line.
Install Turbine, point it at Postgres, and run your first typed query in minutes.