drizzle-team/drizzle-orm · error · Error

Transactions are not supported by the Postgres Proxy driver

Error message

Transactions are not supported by the Postgres Proxy driver

What it means

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.

Source

Thrown at drizzle-orm/src/pg-proxy/session.ts:74

			this.client,
			query.sql,
			query.params,
			query.typings,
			this.logger,
			this.cache,
			queryMetadata,
			cacheConfig,
			fields,
			isResponseInArrayMode,
			customResultMapper,
		);
	}

	override async transaction<T>(
		_transaction: (tx: PgProxyTransaction<TFullSchema, TSchema>) => Promise<T>,
		_config?: PgTransactionConfig,
	): Promise<T> {
		throw new Error('Transactions are not supported by the Postgres Proxy driver');
	}
}

export class PgProxyTransaction<
	TFullSchema extends Record<string, unknown>,
	TSchema extends TablesRelationalConfig,
> extends PgTransaction<PgRemoteQueryResultHKT, TFullSchema, TSchema> {
	static override readonly [entityKind]: string = 'PgProxyTransaction';

	override async transaction<T>(
		_transaction: (tx: PgProxyTransaction<TFullSchema, TSchema>) => Promise<T>,
	): Promise<T> {
		throw new Error('Transactions are not supported by the Postgres Proxy driver');
	}
}

export class PreparedQuery<T extends PreparedQueryConfig> extends PreparedQueryBase<T> {
	static override readonly [entityKind]: string = 'PgProxyPreparedQuery';

View on GitHub (pinned to b7862528fd)

Solutions

  1. 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.
  2. 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.
  3. 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.

Example fix

// before (pg-proxy, throws)
import { drizzle } from 'drizzle-orm/pg-proxy';
const db = drizzle(remoteCallback);
await db.transaction(async (tx) => {
  await tx.insert(users).values({...});
});

// after (postgres-js, transactions supported)
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';
const db = drizzle(postgres(process.env.DATABASE_URL!));
await db.transaction(async (tx) => {
  await tx.insert(users).values({...});
});
Defensive patterns

Strategy: validation

Validate before calling

// Before using transactions, detect the proxy driver and branch.
import { is } from 'drizzle-orm/entity';
import { PgRemoteSession } from 'drizzle-orm/pg-proxy/session';

function supportsTransactions(db: any): boolean {
  // The pg-proxy session's transaction is the throwing override;
  // treat PgRemoteSession as unsupported.
  return !is(db.$client, PgRemoteSession) && !is(db.session, PgRemoteSession);
}

if (supportsTransactions(db)) {
  await db.transaction(async (tx) => { /* ... */ });
} else {
  await runSequentiallyWithoutTransaction();
}

Type guard

import { entityKind } from 'drizzle-orm/entity';

function isPgProxyDb(db: any): boolean {
  const session = db?.session;
  return session?.[entityKind] === 'PgRemoteSession';
}

Try / catch

try {
  await db.transaction(async (tx) => { /* ... */ });
} catch (e) {
  if (e instanceof Error && /Transactions are not supported by the Postgres Proxy driver/.test(e.message)) {
    // fall back to sequential non-transactional writes with compensation
  } else throw e;
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of drizzle-team/drizzle-orm@b7862528fd (2026-08-03). Data as JSON: /data/errors/49bb29099f68048d.json. Report an issue: GitHub.