Replies: 6 comments 1 reply
|
prisma in edge runtime has the same fundamental problem as any other tcp client: edge functions cannot keep a tcp connection open between requests. the fix is to use with the neon adapter: import { PrismaNeon } from "@prisma/adapter-neon";
import { Pool } from "@neondatabase/serverless";
import { PrismaClient } from "@prisma/client";
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
const adapter = new PrismaNeon(pool);
const prisma = new PrismaClient({ adapter });also add if you are not using neon, look at |
|
There isn't a Prisma-specific singleton that can be shared across Vercel Edge invocations. A module-level client may be reused while the same isolate stays warm, but it is not a cross-request/global pool and you cannot rely on it to cap PostgreSQL connections. So the decision is basically: // Keep this route on Node if you want normal TCP pooling/PgBouncer behavior
export const runtime = 'nodejs'or stay on Edge and use an Edge-compatible Prisma path, e.g. For high-throughput complex SQL, I would keep the DB-heavy route on |
|
@yakubka Thanks for the Neon adapter suggestion! But I have a concern: const pool = new Pool({ connectionString: process.env.DATABASE_URL });
const adapter = new PrismaNeon(pool);
const prisma = new PrismaClient({ adapter });This creates a Pool per module load, but in Edge runtime each invocation is a separate isolate. So:
The pool never actually "pools" across requests. It's just a fancy connection wrapper at that point. Am I misunderstanding how Neon's serverless driver handles this? @barry166 Good point about keeping DB-heavy routes on Node.js. But what about this pattern: // Edge middleware for auth (fast, no DB)
export async function middleware(req) {
const token = req.cookies.get('token');
if (!verifyJWT(token)) return NextResponse.redirect('/login');
}
// Node.js route for DB work
export const runtime = 'nodejs';
export async function GET() {
const users = await prisma.user.findMany();
return Response.json(users);
}Is this the recommended hybrid approach? Edge for stateless auth/routing, Node.js for anything DB-heavy? Also, for read-heavy routes, would Accelerate caching be worth the latency tradeoff? const products = await prisma.product.findMany({
cacheStrategy: { ttl: 60 }
});Or is it better to just use Node.js + Redis for caching? |
|
Dude i dont even know who u are
…On Sat, Jul 11, 2026, 1:44 AM Yokubjon ***@***.***> wrote:
you are correct that the Pool object does not pool across edge
invocations. the naming is misleading.
what PrismaNeon with the Pool from neondatabase serverless does is
communicate over http or websockets instead of tcp. the pooling in the name
refers to neon infrastructure-side connection pooling, not a client-side
pool you control.
the correct mental model is:
- your edge function creates a new http client on cold start
- neon servers maintain the actual postgres connection pool on their
side
- you are not opening a new postgres connection per request. neon
routes your http request to an existing pooled connection on their
infrastructure
so the benefit is not client-side pooling. it is that you are never
opening a raw tcp connection, which edge runtime does not allow anyway. the
pool on neon side means postgres does not see a new connection per request
even though your edge function does not persist anything between
invocations.
if you need true connection pooling under your own control, node.js
runtime plus pgbouncer is the only path.
—
Reply to this email directly, view it on GitHub
<#29692?email_source=notifications&email_token=CGXYJJ5HFRL62LYENJXDQIL5EHO6HA5CNFSNUABIM5UWIORPF5TWS5BNNB2WEL2ENFZWG5LTONUW63SDN5WW2ZLOOQXTCNZWGAZTOOJUUZZGKYLTN5XKU43VMJZWG4TJMJSWJJLFOZSW45FMMZXW65DFOJPWG3DJMNVQ#discussioncomment-17603794>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/CGXYJJ43OKVUCHTRWI2FDDT5EHO6HAVCNFSNUABIKJSXA33TNF2G64TZHMYTSMRZGI2TQMZTHNCGS43DOVZXG2LPNY5TCMBTGY4TEMRRUF3AE>
.
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
|
|
The thing biting you is really two problems stacked together. First, the Vercel Edge runtime can't open raw TCP sockets at all. Second, even on the Node serverless runtime every isolate that spins up makes its own pool, so You fix it at the right layer: 1. Don't talk to Postgres directly over TCP from the edge. Use something HTTP based instead:
Accelerate version: import { PrismaClient } from "@prisma/client/edge";
import { withAccelerate } from "@prisma/extension-accelerate";
const prisma = new PrismaClient().$extends(withAccelerate());
export const runtime = "edge";
export async function GET() {
const users = await prisma.user.findMany();
return Response.json(users);
}2. If you drop back to the Node runtime, stick a real pooler in front of Postgres (PgBouncer, the Supabase pooler, RDS Proxy) in transaction mode, point Short version: edge means Accelerate or an HTTP driver adapter, node serverless means an external pooler in transaction mode with If this helped you out, would appreciate it if you selected it as the answer. |
|
Thats what i ment
…On Sat, Jul 11, 2026, 1:40 PM JosephHampton ***@***.***> wrote:
The thing biting you is really two problems stacked together. First, the
Vercel Edge runtime can't open raw TCP sockets at all. Second, even on the
Node serverless runtime every isolate that spins up makes its own pool, so new
PrismaClient() times your concurrency is what blows the connection count
up.
You fix it at the right layer:
*1. Don't talk to Postgres directly over TCP from the edge.* Use
something HTTP based instead:
- *Prisma Accelerate* ***@***.***/extension-accelerate), a managed pooler
plus edge cache that Prisma talks to over HTTP. This is the "just works on
edge" option.
- Or a serverless *driver adapter* that speaks HTTP:
@prisma/adapter-neon, @prisma/adapter-planetscale, @prisma/adapter-d1,
etc. Those use the provider's HTTP driver instead of a raw socket.
Accelerate version:
import { PrismaClient } from ***@***.***/client/edge";import { withAccelerate } from ***@***.***/extension-accelerate";
const prisma = new PrismaClient().$extends(withAccelerate());
export const runtime = "edge";export async function GET() {
const users = await prisma.user.findMany();
return Response.json(users);}
*2. If you drop back to the Node runtime,* stick a real pooler in front
of Postgres (PgBouncer, the Supabase pooler, RDS Proxy) in *transaction
mode*, point DATABASE_URL at the pooler port, and add
?pgbouncer=true&connection_limit=1 so each instance only ever holds one
connection. Keep the client in module scope like you already do so it gets
reused between invocations.
Short version: edge means Accelerate or an HTTP driver adapter, node
serverless means an external pooler in transaction mode with
connection_limit=1. A plain PrismaClient going straight to Postgres over
TCP is always going to exhaust the pool once you get real traffic.
If this helped you out, would appreciate it if you selected it as the
answer.
—
Reply to this email directly, view it on GitHub
<#29692?email_source=notifications&email_token=CGXYJJYD3BZYO6DE2ZUMCHL5EKCYHA5CNFSNUABIM5UWIORPF5TWS5BNNB2WEL2ENFZWG5LTONUW63SDN5WW2ZLOOQXTCNZWGA3TONRZUZZGKYLTN5XKOY3PNVWWK3TUUVSXMZLOOSWGM33PORSXEX3DNRUWG2Y#discussioncomment-17607769>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/CGXYJJ24E2HJJLCHMPZ7CSL5EKCYHAVCNFSNUABIKJSXA33TNF2G64TZHMYTSMRZGI2TQMZTHNCGS43DOVZXG2LPNY5TCMBTGY4TEMRRUF3AE>
.
You are receiving this because you commented.Message ID:
***@***.***>
|
Uh oh!
There was an error while loading. Please reload this page.
Problem
I am deploying a Next.js app with Prisma to Vercel Edge Functions. Each edge function creates a new database connection, which quickly exhausts the connection pool.
Architecture
With 1000 concurrent users, I get 1000 connections to my PostgreSQL database.
Current approach
Problems
What I tried
Questions
Environment
Any insights on Prisma edge deployment patterns would be appreciated.
All reactions