Question

Drizzle on Supabase: 'prepared statement "xyz" does not exist' only in production

Solved · 312 viewsasked by tuan_ng

Next.js app on Vercel, Drizzle ORM with postgres-js, Supabase database. Locally everything is fine. In production maybe one in ten requests fails with:

PostgresError: prepared statement "8f3a1c2e" does not exist

or sometimes prepared statement ... already exists. Retrying the same request usually works. My DATABASE_URL is the one from the Connect dialog with port 6543.

What I’ve tried

Claude Code suggested wrapping every query in a retry. That works but feels like a bandaid. Restarted the Supabase project, no change.

Comment
Same thing bit me with Drizzle on Vercel last month. prepare: false should honestly be in the default snippet. bea_quinn

3 answers

Marked as helpful by the asker
jb_supa

Port 6543 is the transaction pooler. In transaction mode each query can land on a different backend connection, so a prepared statement created on one connection isn't there on the next. postgres-js prepares statements by default.

const client = postgres(process.env.DATABASE_URL!, { prepare: false })
export const db = drizzle({ client })

Locally it works because you're probably hitting the local database directly, no pooler in between. Remove the retry wrapper after this, it hides real errors.

Comment
That was it, zero errors since. Removing the retry now. tuan_ng
ximena_c

If you also run drizzle-kit migrations, point those at the session pooler (port 5432) or the direct connection, not 6543. Migrations like having one connection for the whole run.

Comment
good to know, my drizzle.config uses the same URL. changing it tuan_ng
nadia_r

If you switch to node-postgres (pg) instead: it only prepares statements when you give a query a name, so it works with the transaction pooler out of the box. But prepare: false is the smaller change.

Comment
Staying on postgres-js with prepare: false for now, but good to know if I ever switch. tuan_ng