The singleton helps within one function instance, but on Vercel you have many instances, each holding its own connections, straight to Postgres on 5432. Small Supabase instances only allow a limited number of direct connections, so 30 users can fill them.
Use the pooler for the app and keep the direct connection for migrations only:
# .env (Vercel)
DATABASE_URL="postgresql://postgres.abcd:[pw]@aws-0-eu-central-1.pooler.supabase.com:6543/postgres?pgbouncer=true&connection_limit=1"
DIRECT_URL="postgresql://postgres.abcd:[pw]@aws-0-eu-central-1.pooler.supabase.com:5432/postgres"
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
directUrl = env("DIRECT_URL")
}Port 6543 is transaction mode: connections go back to the pool after each transaction. pgbouncer=true stops Prisma from using prepared statements, which transaction mode does not support.