Moving to Bun, adding DataLoaders, and keeping the output byte-for-byte identical.
A GraphQL service had multi-second p99s on a handful of operations. The cause wasn't the database — it was the shape of the work: N+1 resolvers firing hundreds of round trips per request.
The fix, in three steps
- DataLoaders — one loader per relation, created per request, so a list of 50 items becomes one batched query instead of 50.
- Runtime move to Bun — faster startup and I/O, adopted only after the test suite passed unchanged.
- Byte-for-byte verification — replay production traffic against old and new, comparing raw response bytes. Parsed comparison hides key-order changes; byte comparison doesn't.
The lesson: performance work on a live API is a migration, not a refactor. Batch the queries, then prove clients see identical pages before you celebrate. Roll out behind a flag, watch p99 and error rate, and keep the old path one deploy away until the numbers hold.