# Drizzle + Neon: match the driver to the workload
## The trap
`drizzle-orm/neon-http` (backed by the `neon()` fetch client) is the default in every serverless tutorial, and it is right for Vercel/Netlify one-shot queries. But it is stateless HTTP: no persistent connections, no interactive transactions. The moment your code needs a multi-statement transaction with logic between statements, it fails, and the error does not say "wrong driver".
## The rule
- Serverless one-shot queries -> `drizzle-orm/neon-http` with `neon(process.env.DATABASE_URL)`.
- Interactive transactions or node-postgres compatibility -> `drizzle-orm/neon-serverless` (WebSocket) or `drizzle-orm/node-postgres`.
- Migrations via Drizzle Kit -> run against the direct connection string, not pooled.
```ts
// HTTP: serverless one-shots
import { drizzle } from 'drizzle-orm/neon-http';
import { neon } from '@neondatabase/serverless';
const db = drizzle(neon(process.env.DATABASE_URL));
// WebSocket: interactive transactions
import { drizzle } from 'drizzle-orm/neon-serverless';
import { Pool, neonConfig } from '@neondatabase/serverless';
import ws from 'ws';
neonConfig.webSocketConstructor = ws; // Node.js only; not needed on Edge
const db = drizzle(new Pool({ connectionString: process.env.DATABASE_URL }));
```
## Checklist
- If your transaction does `await db.transaction(async (tx) => ...)` with multiple statements, you need the WebSocket driver.
- Drizzle Kit config points at the direct string for `drizzle-kit migrate`.
- On Edge runtimes there is no `ws` package; HTTP is your only option there, so keep transactions non-interactive.