{"id":"49bb29099f68048d","repo":"drizzle-team/drizzle-orm","slug":"transactions-are-not-supported-by-the-postgres-pro","errorCode":null,"errorMessage":"Transactions are not supported by the Postgres Proxy driver","messagePattern":"Transactions are not supported by the Postgres Proxy driver","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"drizzle-orm/src/pg-proxy/session.ts","lineNumber":74,"sourceCode":"\t\t\tthis.client,\n\t\t\tquery.sql,\n\t\t\tquery.params,\n\t\t\tquery.typings,\n\t\t\tthis.logger,\n\t\t\tthis.cache,\n\t\t\tqueryMetadata,\n\t\t\tcacheConfig,\n\t\t\tfields,\n\t\t\tisResponseInArrayMode,\n\t\t\tcustomResultMapper,\n\t\t);\n\t}\n\n\toverride async transaction<T>(\n\t\t_transaction: (tx: PgProxyTransaction<TFullSchema, TSchema>) => Promise<T>,\n\t\t_config?: PgTransactionConfig,\n\t): Promise<T> {\n\t\tthrow new Error('Transactions are not supported by the Postgres Proxy driver');\n\t}\n}\n\nexport class PgProxyTransaction<\n\tTFullSchema extends Record<string, unknown>,\n\tTSchema extends TablesRelationalConfig,\n> extends PgTransaction<PgRemoteQueryResultHKT, TFullSchema, TSchema> {\n\tstatic override readonly [entityKind]: string = 'PgProxyTransaction';\n\n\toverride async transaction<T>(\n\t\t_transaction: (tx: PgProxyTransaction<TFullSchema, TSchema>) => Promise<T>,\n\t): Promise<T> {\n\t\tthrow new Error('Transactions are not supported by the Postgres Proxy driver');\n\t}\n}\n\nexport class PreparedQuery<T extends PreparedQueryConfig> extends PreparedQueryBase<T> {\n\tstatic override readonly [entityKind]: string = 'PgProxyPreparedQuery';","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/drizzle-team/drizzle-orm/blob/b7862528fd8fc39bc2653a6c18dad7c1f4e68d10/drizzle-orm/src/pg-proxy/session.ts#L56-L92","documentation":"This error is thrown by PgRemoteSession.transaction() because the Postgres Proxy driver (drizzle-orm/pg-proxy) executes queries over a stateless remote callback (HTTP/RPC) and cannot open a real PostgreSQL transaction. Transactions require a persistent connection, BEGIN/COMMIT, and a session that the proxy protocol does not expose. The driver overrides transaction() to fail fast rather than silently no-op.","triggerScenarios":"Calling db.transaction(async (tx) => {...}) on a database instance built with drizzle()'s pg-proxy driver (RemoteCallback). This includes any relational query builder that internally needs a transaction, or direct use of db.transaction() in application code after initializing via drizzle(remoteCallback).","commonSituations":"Developers migrating from node-postgres or pg-driver code that used transactions, then deploying to an edge/serverless platform with the pg-proxy driver. Copying example transaction code from docs that assumes a socket driver. Using the Supabase/Neon HTTP RPC edge driver and attempting transactions.","solutions":["Switch to a driver that supports transactions: drizzle-orm/node-postgres, drizzle-orm/postgres-js, drizzle-orm/vercel-postgres (which supports transactions via pool), or neon-serverless with a WebSocket/HTTP transactional API.","If you must stay on pg-proxy, restructure logic to avoid transactions: run statements sequentially and implement application-level idempotency/compensating logic instead of BEGIN/COMMIT.","If using Supabase edge, check drizzle-orm/neon-http vs neon-serverless; neon-serverless over WebSocket supports transactions while neon-http (proxy-like) does not."],"exampleFix":"// before (pg-proxy, throws)\nimport { drizzle } from 'drizzle-orm/pg-proxy';\nconst db = drizzle(remoteCallback);\nawait db.transaction(async (tx) => {\n  await tx.insert(users).values({...});\n});\n\n// after (postgres-js, transactions supported)\nimport { drizzle } from 'drizzle-orm/postgres-js';\nimport postgres from 'postgres';\nconst db = drizzle(postgres(process.env.DATABASE_URL!));\nawait db.transaction(async (tx) => {\n  await tx.insert(users).values({...});\n});","handlingStrategy":"validation","validationCode":"// Before using transactions, detect the proxy driver and branch.\nimport { is } from 'drizzle-orm/entity';\nimport { PgRemoteSession } from 'drizzle-orm/pg-proxy/session';\n\nfunction supportsTransactions(db: any): boolean {\n  // The pg-proxy session's transaction is the throwing override;\n  // treat PgRemoteSession as unsupported.\n  return !is(db.$client, PgRemoteSession) && !is(db.session, PgRemoteSession);\n}\n\nif (supportsTransactions(db)) {\n  await db.transaction(async (tx) => { /* ... */ });\n} else {\n  await runSequentiallyWithoutTransaction();\n}","typeGuard":"import { entityKind } from 'drizzle-orm/entity';\n\nfunction isPgProxyDb(db: any): boolean {\n  const session = db?.session;\n  return session?.[entityKind] === 'PgRemoteSession';\n}","tryCatchPattern":"try {\n  await db.transaction(async (tx) => { /* ... */ });\n} catch (e) {\n  if (e instanceof Error && /Transactions are not supported by the Postgres Proxy driver/.test(e.message)) {\n    // fall back to sequential non-transactional writes with compensation\n  } else throw e;\n}","preventionTips":["Decide your driver based on whether you need transactions before wiring Drizzle into the app.","Encapsulate db.transaction calls behind a repository interface so the driver can be swapped without touching call sites.","In serverless/edge deployments, prefer drivers documented to support transactions (neon-serverless over WS, vercel-postgres pool)."],"tags":["postgres","transactions","proxy-driver","serverless","configuration"],"analyzedSha":"b7862528fd8fc39bc2653a6c18dad7c1f4e68d10","analyzedAt":"2026-08-03T18:11:14.318Z","schemaVersion":2}