Drizzle returns nested posts from one findMany call
1 month ago
Drizzle ORM returns a user with an array of posts from one findMany call. That call is db.query.users.findMany, with posts true. Ada comes back with two posts already nested. The SQL Drizzle sent is one statement. drizzle-orm 0.45.2. Episode one of this series left a row in users. This sitting adds posts and reads both back in one call.
Ask about this presentation
Chapters
0:00Nested posts from one findMany
0:24Two lines install Drizzle
0:480.45.2 still takes schema
1:19users table and posts table
1:36Relations go in under schema
2:00Ada and two nested posts
2:14A single SQL statement
2:290.45.2 toSQL is one left join lateral
3:07The relations graph is application-level
3:380.45.2 needs both sides of the graph
4:05schema plus drizzle plus findMany
4:27Nested JavaScript from one SQL statement
4:49db.query.users is undefined
5:23Pasting defineRelations fails to compile
6:05many posts throws until one users
6:28If you delete the relations objects
Show transcriptHide transcript
Drizzle ORM returns a user with an array of posts from one findMany call. That call is db.query.users.findMany, with posts true. Ada comes back with two posts already nested. The SQL Drizzle sent is one statement. drizzle-orm 0.45.2. Episode one of this series left a row in users. This sitting adds posts and reads both back in one call.
Install is two lines. bun add drizzle-orm at 0.45.2 and pg puts the query builder and the PostgreSQL driver in the project. bun add dash d drizzle-kit at 0.31.10 adds the command line tool as a development dependency. The first command installed thirty eight packages in three and seven tenths of a second.
drizzle-orm 0.45.2 and drizzle-kit 0.31.10, on PostgreSQL. This is the stable line. A version one is on the way, 1.0.0 release candidate 4. The live Query page currently installs drizzle-orm at rc, and shows defineRelations. 0.45.2 still takes the tables and the relations objects under the name schema. The live docs pass a v2 object under the name relations. Mix the keys. db.query comes back empty.
The smallest program starts here. It returns nested rows. schema dot ts now has two tables. users is already in the series, with id, name, a unique email, and a created-at stamp. posts adds a title, content, and an authorId column pointing at the user.
Two relations exports. usersRelations says users have many posts. postsRelations says a post has one author, matching authorId to users.id. Pass the tables and those relation objects into drizzle under the name schema. db.query is compiled from that schema object. db.select from users still works if you skip the schema object. db.query.users needs the schema object.
bun index dot ts prints one user, Ada. posts is an array of two objects. Title one, SQL is awesome. Title two, But check relational queries. The posts array is already grouped on the way out.
On the Query page, under Partial fields select, the manual says keep in mind that a single SQL statement is outputted by Drizzle. findMany with posts true can return a nested object. Drizzle compiles one statement.
toSQL on 0.45.2 prints one select, a left join lateral, and json_agg of json_build_array. LATERAL means Postgres runs the inner select once per user row. json_agg packs those related rows into one JSON array in the same SELECT. The driver never groups a flat join list. The live Include-subqueries block is the v2 generator. It uses row_to_json and aliases d0 and d1. Our capture uses json_build_array. The capture is the proof. The Relations page Select with joins tab is leftJoin plus a mappedResult you write yourself. Relational queries skip that mapping.
On the Relations page, the Foreign keys section. Relations do not affect the database schema in any way and do not create foreign keys implicitly. Two schemas, one with foreign keys and one without, will work exactly the same for relational queries. The relations graph is a TypeScript object that says which tables point at which. db.query reads that object. Our lab has the foreign key and the relations graph. db.query reads the graph. The references call on authorId is for migrations.
usersRelations says many posts. findMany with posts true still throws until postsRelations declares one users, with fields and references. The error reads There is not enough information to infer relation users.posts. The v1 to v2 page names this Define many without one. The v2 line can declare many alone. 0.45.2 still needs both sides of the graph. The matching one is what lets with posts true compile a join.
schema exports users, posts, usersRelations, and postsRelations. index imports the whole file as schema. drizzle gets the connection string and that schema object. Then db.query.users.findMany, with posts true. with posts true is how you ask for the nested array. The Query page columns option picks which fields come back. It still emits one statement.
bun index prints Ada, posts already nested. Two titles: SQL is awesome, and But check relational queries. bun tosql prints one select, left join lateral, json_agg of json_build_array. Declare the graph. Pass it as schema on 0.45.2. Call db.query. Nested JavaScript comes back from one SQL statement.
This is the part people get wrong. db.select from users works. db.query.users is undefined. That is drizzle-orm issue 4390, closed January 2026, labelled rqb. drizzle never received the graph. On 0.45.2, omit schema. query keys prints an empty array. Pass the live-docs key relations. You get the same empty query. Tables only in schema is quieter. query.users exists. with posts true throws relation.referencedTable. On the rc line the empty-query miss is omitting relations.
This is the part people get wrong. The Query and Relations pages install drizzle-orm at rc and show defineRelations. The docs skip this. npm i drizzle-orm still gives 0.45.2. Paste the live snippet onto 0.45.2 and Bun throws SyntaxError: Export named defineRelations not found. tsc says TS2305, no exported member defineRelations. tsc also says relations does not exist in type DrizzleConfig. The v1 to v2 page renames the option from schema to relations. Mix the names. db.query is empty. The v1 form that compiles is relations per table, passed as schema.
This is the part people get wrong. On 0.45.2, usersRelations with only many posts throws There is not enough information to infer relation users.posts. The matching postsRelations, one users with fields and references, is what lets with posts true compile a join. The v1 to v2 page calls this Define many without one.
The whole path is two tables, two relations exports, schema into drizzle, and one findMany with posts true. A nested object comes back. One SQL statement went out. drizzle-orm 0.45.2, drizzle-kit 0.31.10. If you delete the relations objects and keep the foreign keys, what does db.query still know?
Up next
6:49AI SDK 7 Output.object returns a typed object or throws
@the-manual · 4 weeks ago
6:49AI SDK 7 streamText calls a typed weather tool
@the-manual · 4 weeks ago
5:22AI SDK 7 streams a terminal response with streamText
@the-manual · 1 month ago
5:13Bun.cron schedules a TypeScript job without node-cron
@the-manual · 1 month ago
5:56Drizzle leftJoin returns nullable pet rows
@the-manual · 1 month ago
6:59Bun SQLite printed Ada and Grace from a file next to the code
@the-manual · 1 month ago
6:58Drizzle schema file to first applied migration
@the-manual · 1 month ago
7:07Bun 1.4 — install to a running HTTP server
@the-manual · 2 months ago
3:41Build a typed API in 10 minutes with tRPC — no codegen, no schemas
@the-manual · 2 months ago
3:41Build a typed API in 10 minutes with tRPC — no codegen, no schemas
@the-manual · 2 months ago