Skip to content

How much memory does an ORM cost per request?

Someone on r/bun asked how UQL’s RAM usage compares to Drizzle’s. I didn’t have an answer, so I measured it: weigh the heap, run the query, weigh it again, subtract.

Bun reported zero. JavaScriptCore refreshes heapUsed only when it collects, so every entry looked like it had allocated nothing. The memory run is on Node, minus the two Bun SQL entries.

A forced global.gc() added 19%. It frees compiled code along with the garbage, and the rounds after it re-optimise as they run, allocating extra.

One process ranked them by start order. The first entry paid to JIT what the rest inherited warm. One process per entry now.

Against hand-written raw pg, rows mapped by hand, so what you see is the ORM’s own allocation.

Entry Total KB Adds KB
raw pg 245 floor
UQL 446 +201
Drizzle 769 +524
Prisma 1,053 +808
TypeORM 1,065 +820
Sequelize 1,296 +1,051
MikroORM 3,864 +3,619

18x between lightest and heaviest, where the same lifecycle in time spans 10x. One step causes nearly all of it: the nested read, the only one that turns two result sets into an object graph, costs UQL 184KB and MikroORM 2,060KB.

Sixty more lifecycles, collected either side, leave the worst entry 42KB heavier (Sequelize), identity maps and all. What the table prices is the garbage each request hands the collector, not memory that stays.

UQL adds 201KB per request, Drizzle 524KB, MikroORM 3.6MB. That is allocation, not resident memory, on one machine with no pooling and no concurrency.

Run it yourself: bun run bench.memory rewrites the table it publishes, so the current numbers can never drift from the last run.



UQL is a JSON-native ORM for Node.js, Bun and Deno. Supports PostgreSQL, PGlite, MySQL, MariaDB, SQLite, CockroachDB, Turso, Neon, Cloudflare D1 and MongoDB. Queries are plain JSON, typed to the leaf.