drizzle-team/drizzle-orm · error · Error

No transactions support in neon-http driver

Error message

No transactions support in neon-http driver

What it means

An Error 'No transactions support in neon-http driver' thrown by NeonHttpSession.transaction() (drizzle-orm/src/neon-http/session.ts:253). The neon-http driver issues each query as an independent HTTPS fetch to Neon; there is no persistent connection over which to hold a transaction open, so db.transaction() is intentionally unimplemented and throws synchronously.

Source

Thrown at drizzle-orm/src/neon-http/session.ts:253

	override async count(sql: SQL): Promise<number>;
	/** @internal */
	override async count(sql: SQL, token?: NeonAuthToken): Promise<number>;
	/** @internal */
	override async count(sql: SQL, token?: NeonAuthToken): Promise<number> {
		const res = await this.execute<{ rows: [{ count: string }] }>(sql, token);

		return Number(
			res['rows'][0]['count'],
		);
	}

	override async transaction<T>(
		_transaction: (tx: NeonTransaction<TFullSchema, TSchema>) => Promise<T>,
		// eslint-disable-next-line @typescript-eslint/no-unused-vars
		_config: PgTransactionConfig = {},
	): Promise<T> {
		throw new Error('No transactions support in neon-http driver');
	}
}

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

	override async transaction<T>(_transaction: (tx: NeonTransaction<TFullSchema, TSchema>) => Promise<T>): Promise<T> {
		throw new Error('No transactions support in neon-http driver');
		// const savepointName = `sp${this.nestedIndex + 1}`;
		// const tx = new NeonTransaction(this.dialect, this.session, this.schema, this.nestedIndex + 1);
		// await tx.execute(sql.raw(`savepoint ${savepointName}`));
		// try {
		// 	const result = await transaction(tx);
		// 	await tx.execute(sql.raw(`release savepoint ${savepointName}`));
		// 	return result;

View on GitHub (pinned to b7862528fd)

Solutions

  1. Switch to drizzle-orm/neon-serverless with a WebSocket Pool (@neondatabase/serverless Pool) which supports transactions.
  2. Or use drizzle-orm/node-postgres against Neon for serverful apps.
  3. If staying on neon-http, restructure to single statements or use Neon's HTTP transaction endpoint if available.

Example fix

// before
import { neon, drizzle } from 'drizzle-orm/neon-http';
const db = drizzle(neon(process.env.DATABASE_URL!));
await db.transaction(async (tx) => { /* ... */ }); // throws

// after — neon-serverless WebSocket pool supports transactions
import { Pool } from '@neondatabase/serverless';
import { drizzle } from 'drizzle-orm/neon-serverless';
const db = drizzle(new Pool({ connectionString: process.env.DATABASE_URL! }));
await db.transaction(async (tx) => { /* ... */ });
Defensive patterns

Strategy: validation

Validate before calling

import { NeonHttpSession } from 'drizzle-orm/neon-http';

function supportsTransactions(db: any): boolean {
  return !(db?.session instanceof NeonHttpSession);
}

if (!supportsTransactions(db)) {
  throw new Error('neon-http cannot run transactions; use drizzle-orm/neon-serverless (Pool).');
}

Type guard

import { NeonHttpSession } from 'drizzle-orm/neon-http';

function isNeonHttp(db: any): boolean {
  return db?.session instanceof NeonHttpSession;
}

Try / catch

try {
  await db.transaction(async (tx) => { /* ... */ });
} catch (e) {
  if (e instanceof Error && /No transactions support in neon-http driver/i.test(e.message)) {
    throw new Error('Switch to drizzle-orm/neon-serverless (WebSocket Pool) for transactions.');
  }
  throw e;
}

Prevention

When it happens

Trigger: Constructing the DB with drizzle-orm/neon-http's drizzle(neon(process.env.DATABASE_URL)) and calling db.transaction(async tx => { ... }). The override throws immediately regardless of config.

Common situations: Using neon-http for cheapest cold-start in serverless/edge, then reaching for db.transaction() in business logic. Developers expect transaction support because Neon is a real Postgres, but the HTTP transport cannot keep a tx alive between round trips.

Related errors


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