Back to Blog

Prisma Cold Start Latency on AWS Lambda — Why Every Request Is Slow

Published: July 28, 2026
Prisma Cold Start Latency on AWS Lambda — Why Every Request Is Slow

Prisma cold start latency on AWS Lambda hits the same way every time: the first request to land on a freshly spun-up Lambda instance eats a multi-second penalty before your query even runs, while every subsequent request against that same warm instance is fast. It's consistent, it's predictable, and it's easy to misdiagnose as a database problem when the actual cost happens entirely before Prisma ever talks to Postgres.

Short answer: Prisma has real, documented per-cold-start costs — module loading, runtime interpretation, and query engine initialization — and the single most common way projects make that worse than it needs to be is bundling every binaryTargets platform they've ever developed on into the production Lambda package, bloating exactly the module-loading step that's already the biggest cost. Trim the binary targets to what Lambda actually runs, and treat provisioned concurrency as a cost tradeoff for predictable traffic rather than a fix for the underlying mechanism.

Intricate frost patterns forming on a window in winter light, representing the cold start penalty every fresh Lambda instance pays before Prisma runs a single query

Where Prisma's Cold Start Cost Actually Comes From

Prisma's own engineering team has documented the real breakdown of what a cold Lambda invocation pays for, and none of it is your query: downloading and extracting the Prisma Client package (module loading), parsing and interpreting that code at runtime, initializing the query engine and building its internal schema structures, and only then opening the actual database connection. A warm instance reusing an existing container skips all of this — which is exactly why the first request per instance is consistently slow while every request after it is fast.

(If you've been staring at your query's EXPLAIN ANALYZE output looking for the slow part — it's not there. By the time your query reaches Postgres, the expensive part already happened, several layers up, before your code had a chance to do anything wrong.)

The Overlooked Cause: Bloated binaryTargets

The single most common way projects make this worse than necessary is leaving schema.prisma configured with every platform they've ever developed or tested on:

PRISMA
1// prisma/schema.prisma — WRONG: bundling dev-machine and CI platforms into the Lambda deployment
2generator client {
3  provider      = "prisma-client-js"
4  binaryTargets = ["native", "debian-openssl-1.1.x", "rhel-openssl-3.0.x"]
5}

Every entry in that array ships an entire platform-specific query engine binary inside your deployment package — whether or not that platform is the one actually running in production. A package carrying three engine binaries when Lambda only ever needs one is directly bloating the module-loading step that's already the largest documented cold-start cost. The fix is scoping the production build to exactly what Lambda runs:

PRISMA
1// prisma/schema.prisma — RIGHT: only the binary target Lambda's runtime actually needs
2generator client {
3  provider      = "prisma-client-js"
4  binaryTargets = ["rhel-openssl-3.0.x"]
5}

rhel-openssl-3.0.x matches Lambda's standard x86_64 runtime; use the ARM64 equivalent if you're deploying to Graviton-based functions instead. Prisma's schema reference documents the full list of valid binaryTargets values if your runtime isn't standard Lambda. Keep native for your local development schema if you need it, but the production build that actually gets zipped and uploaded to Lambda shouldn't be carrying binaries for platforms it will never run on.

A large, disorganized pile of suitcases in an airport terminal, representing a deployment package bloated with binary targets the Lambda runtime never actually uses

Provisioned Concurrency: A Cost Tradeoff, Not a Fix

AWS's own provisioned concurrency documentation covers the mechanism directly: it keeps a specified number of Lambda instances permanently warm, which eliminates cold start latency entirely for the traffic those instances absorb — at the ongoing cost of paying for that concurrency whether or not requests actually arrive. It's a reasonable choice for predictable baseline traffic where you know roughly how many concurrent instances you need at any given time. It doesn't reduce the underlying cold-start cost itself, and any burst beyond what you've provisioned still spins up genuinely cold instances paying the full penalty — which means it's a mitigation layered on top of the fixes above, not a substitute for them.

A cozy living room with a lit fireplace and a warm blanket on the sofa, representing provisioned concurrency keeping Lambda instances warm at an ongoing cost

The Fix Most Teams Check Last: Your Prisma Version Itself

Prisma has shipped substantial engine-level performance work across recent versions, including replacing an expensive GraphQL-like query serialization protocol that added measurable overhead on every cold start. Teams running a Prisma version that's more than a year or two old are often carrying cold-start costs that a newer major version has already fixed for free, no configuration change required — worth checking the changelog for engine performance improvements before assuming infrastructure is the only lever available.

The Opinion Part

Here's the position worth stating plainly, and it connects directly to the same instinct behind keeping a Docker image lean instead of bloated: serverless cold starts aren't a single problem with a single fix, they're a stack of independent costs — framework bootstrap, ORM initialization, package size — that each need their own targeted trim. You are not going to provisioned-concurrency your way out of a bloated deployment package, and you're not going to binary-target your way out of a heavy DI container bootstrap. Solve the layer you're actually paying for, measured, rather than reaching for the first fix that shows up in a blog post — the dashboard we cut from 8 seconds to 340ms didn't need new infrastructure either, it needed the specific thing that was actually slow found and fixed.

Conclusion

If Prisma is adding real latency to every cold Lambda instance, check your binaryTargets configuration before reaching for provisioned concurrency — a production build still bundling dev-machine binaries is padding the exact module-loading cost that's already the biggest documented contributor to Prisma's cold start time. Trim it to what Lambda actually runs, confirm you're on a current Prisma version that's benefited from real engine-level performance work, and treat provisioned concurrency as a cost tradeoff for predictable traffic rather than the fix itself.

If NestJS's own bootstrap cost is compounding this on the same Lambda function, our dedicated NestJS cold start guide covers that separate, stackable layer of the same overall symptom.

Trim the binary targets, check your Prisma version, and watch the number that used to make you wince on the first request of every burst quietly stop being something you have to explain to anyone.

Frequently Asked Questions

Prisma's own engineering team has documented the actual breakdown: module loading (downloading and extracting the Prisma Client package), runtime interpretation of that code, query engine initialization (building internal schema structures), and finally the real database connection — every one of which only happens on a genuinely cold instance, not on a warm one reusing an existing container.

Indirectly, but significantly. Every binary target listed in your generator block ships an entire platform-specific engine binary inside your deployment package, whether or not that platform is what actually runs in production. A schema.prisma still listing your local dev machine's binary target alongside Lambda's bloats the package Lambda has to download and extract on every cold start, which is exactly the module-loading cost that drives up the number you're trying to fix.

rhel-openssl-3.0.x for Lambda's standard x86_64 runtime, or the ARM64 equivalent if you're deploying to Graviton-based Lambda functions. The key discipline is listing only the target(s) your actual Lambda function runs on in the deployed build, not every platform you've ever developed or tested on.

It eliminates the symptom for the instances it keeps warm, at a real ongoing cost — you're paying for that concurrency to sit idle and ready regardless of whether traffic arrives. It doesn't reduce the underlying per-cold-start cost itself, and any burst of traffic beyond your provisioned amount still spins up genuinely cold instances that pay the full penalty, so it's a mitigation for predictable baseline traffic, not a fix for the mechanism itself.

Yes, meaningfully, and it's the fix people check last. Prisma has shipped substantial engine-level optimizations over successive versions — including replacing an expensive query-serialization protocol — that measurably reduce cold start cost without any configuration change on your part. If you're troubleshooting cold starts on a Prisma version that's more than a year or two old, checking the changelog for engine performance work is worth doing before reaching for infrastructure-level fixes.

Portrait of Umar Farooq

About Umar Farooq

Umar Farooq is the founder and lead engineer of Codify SaaS. He builds B2B SaaS products and web applications on modern TypeScript stacks and enterprise Java, and writes code-first guides drawn from real production work — the schema decisions, the migrations that almost went wrong, and the performance fixes that actually moved the numbers. When he recommends an approach, he shows the code and explains the trade-offs.

Read full bio