Drizzle + Neon on Vercel: Stop DB Connection Storms (2026)

Akshit Ahuja

Akshit Ahuja

Co-Founder & Lead Engineer

February 21, 2026
#drizzle#neon#vercel#postgres#nextjs#serverless#connection-pooling

If you are using Next.js on Vercel with Drizzle and Neon, you can hit a weird failure mode: your app works in dev, then production gets random 500s and the Neon dashboard shows a wall of connections. The error usually reads like too many connections, or your queries start timing out.

This is not a Drizzle bug. It is not a Neon bug. It is the combo of serverless request patterns plus how you create clients.

I am going to be opinionated: most teams shipping on Vercel should default to HTTP queries (Neon serverless driver) for reads and simple writes, then use pooling only when they truly need interactive transactions. If you pick the wrong mode, you pay for it in latency, outages, and a lot of pager noise.

The actual problem: connection storms

Classic Postgres drivers open TCP connections. In a serverless world, you do not have one long-lived process. You have many short invocations. If each invocation creates its own pool, or if your code runs in multiple regions, you can spawn hundreds of connections fast.

Neon (and most hosted Postgres) has connection limits. When you blow past them, you either get hard errors or slow queries because the database is spending cycles on connection management instead of work.

The sneaky part is that it can look fine at low traffic. Then you get a spike from a Product Hunt launch, a marketing email, or a bot that decided to crawl your whole site. Five minutes later, your database is the bottleneck.

2026 reality check: Vercel has multiple execution modes

In 2026 most Next.js apps on Vercel run a mix of:

- Server Components and Route Handlers (Node runtime)
- Server Actions (Node runtime)
- Sometimes Edge runtime for auth, redirects, geo, or A/B tests

Each mode changes what database connection style even works. Edge cannot speak raw TCP Postgres. Node can. So you need to decide per layer, not per repo.

Pick one of these three patterns

Pattern A: Neon HTTP + Drizzle neon-http (my default)

If you do not need interactive transactions, use the Neon serverless driver over HTTP. Neon recommends HTTP for one-shot queries and it is fast for simple request-response database work.

This avoids the whole pool in a lambda problem. There is no TCP connection to hold open. You call an HTTPS endpoint, you get rows back.

Rough numbers we see in the field: moving from raw TCP connects to HTTP can cut cold-start query overhead by a few round trips. In practice, teams usually see p95 route latency drop by 50-150ms on endpoints that used to open a new connection under load.

Code sketch:

```ts
import { neon } from '@neondatabase/serverless';
import { drizzle } from 'drizzle-orm/neon-http';

const sql = neon(process.env.DATABASE_URL!);
export const db = drizzle(sql);
```

If you do this, stop reading and go ship. This covers a lot of SaaS CRUD apps.

Pattern B: Vercel pooling + pg Pool + Drizzle node-postgres

If you are on Vercel Node runtime and you want classic drivers, you can still make it safe by using connection pooling that survives across invocations. There is a helper in @vercel/functions that attaches a database pool so idle connections close cleanly when the function is frozen.

Fullstack Recipes shows the core idea: create a pg Pool, call attachDatabasePool(pool), then pass the pool into Drizzle.

Code sketch:

```ts
import { attachDatabasePool } from '@vercel/functions';
import { drizzle } from 'drizzle-orm/node-postgres';
import { Pool } from 'pg';

const pool = new Pool({ connectionString: process.env.DATABASE_URL! });
attachDatabasePool(pool);

export const db = drizzle({ client: pool });
```

This pattern is great when you have many queries per request and you want lower per-query overhead. But it is also easier to mess up.

Pattern C: Neon WebSockets + Pool (only when you need it)

Neon also offers WebSocket connections for node-postgres compatibility. This is useful for session features or interactive transactions where HTTP is not enough.

Neon points out a Node version gotcha: for Node versions 21 and earlier you must provide a WebSocket implementation (ws). If your build image is not what you think, you can waste hours on this.

Also, do not create a global pool in an environment that will not keep it around. If the platform kills your process often, you will not get the benefit, and you might create a new pool every time anyway.

The mistakes that cause outages

Mistake 1: creating a Pool inside every request

If your code does this in a Route Handler or Server Action, it is basically a denial-of-service attack you run on yourself:

```ts
export async function GET() {
const pool = new Pool({ connectionString: process.env.DATABASE_URL! });
const rows = await pool.query('select 1');
return Response.json(rows.rows);
}
```

Under real traffic, you create pools faster than Postgres can accept connections.

Mistake 2: mixing drivers across the app

I see teams with neon-http in one file, pg in another, and Prisma somewhere else because someone copied a snippet. Now you have three connection strategies fighting each other. Pick one per runtime: HTTP for Edge and most Node, pooling for heavy Node endpoints.

Mistake 3: forgetting Next.js caching behavior

Neon docs call out something many people miss: Server Components can get statically rendered in production builds. If you run a DB query inside a page that Next.js decides is static, it runs at build time, not per request.

That can be fine, or it can be a faceplant. Your build pipeline might not have DB access, or you might ship stale data. If you need runtime reads, force dynamic rendering for that page or route.

Two gotchas specific to Drizzle + Neon (that waste days)

Gotcha 1: Drizzle Kit runs outside Next.js

Your app can read env vars fine, but drizzle-kit might not, because it is not running inside Next.js. Load env the same way Next does (for example using @next/env) or you will get confusing connection errors when generating or pushing migrations.

Gotcha 2: use the right Drizzle driver

Drizzle supports multiple Neon adapters. If you pass an HTTP client to a driver that expects a pg-compatible Pool, it will not behave the way you think. Decide first: HTTP (drizzle-orm/neon-http) or pooled Node (drizzle-orm/node-postgres). Then keep it consistent.

How we debug this in 30 minutes

When a client says Neon is flaky, we do three quick checks:

1) Search the codebase for new Pool() and count how many times it happens. If it is inside a request handler, that is the smoking gun.

2) Check Vercel regions. If you are deployed to multiple regions but your DB is in one region, cross-region latency plus connection churn makes everything worse.

3) Look at Neon metrics for active connections during a traffic spike. If connections track requests, you are not pooling correctly.

Then we pick a fix:

- If you are mostly CRUD, switch to neon-http + Drizzle neon-http and delete pooling code.
- If you need pooling, move pool creation to module scope and attach it with Vercel helper.
- If you need interactive transactions, use WebSockets, but be honest: most apps do not.

Cost and timeline (real numbers)

If you are a founder in the US or UK paying for a Vercel + Neon stack, the fix is usually cheap. The expensive part is the outage.

Typical rescue effort we see:

- 2-4 hours: audit code paths, find where pools are created, confirm runtime modes
- 2-6 hours: refactor to one connection strategy, add basic load test, deploy
- 1-2 hours: add alerts and dashboards so it does not regress

Ballpark cost: $800 to $3,000 depending on how messy the app is. If the app is already on fire with other issues (bad queries, missing indexes, N+1 in server components), it can be more.

Compare that to one day of downtime on a B2B SaaS doing $5k MRR. You will feel it. People cancel over reliability.

A simple checklist you can copy

Before you ship, answer these:

- Is any database client created inside a request handler? If yes, fix it.
- Are you running Edge runtime anywhere that touches the DB? If yes, use Neon HTTP.
- Do you need interactive transactions? If not, avoid WebSockets.
- Are you using the pooled connection string for production (if you stick with TCP)?
- Is your app deployed in regions far from your database? If yes, expect latency.

My blunt take

Most serverless Postgres is unreliable stories are self-inflicted. The platform does what it says. Your code just creates too many connections because it was written like a long-lived server.

Pick the boring path: Neon HTTP + Drizzle neon-http for the bulk of your app. Use pooling only where it pays off, and keep those code paths small and obvious.

If you want a second set of eyes, HeyDev does these audits fast. We have fixed this exact failure mode for apps that were one traffic spike away from going dark.

---

Related reading

Akshit Ahuja

Akshit Ahuja

Co-Founder & Lead Engineer

Software EngineerBackend Specialist

Backend systems specialist who thrives on building reliable, scalable infrastructure. Akshit handles everything from API design to third-party integrations, ensuring every product HeyDev ships is production-ready.

Related Articles