codexmachina
Component

Every verified stack that runs on Long-running Node (VPS / container).

A persistent Node process: a real connection pool (max ~10, 20) reused across requests.

0 verified stacksHow we verify →

0 verified stacks

No verified stacks published yet.

What Long-running Node (VPS / container) gives you

A persistent Node process — a container, a VPS, a long-lived machine — evaluates `lib/db.ts` exactly once and keeps the result for the process lifetime, which is the condition under which a real driver-side pool earns its keep. `dbClient` emits `postgres(process.env.DATABASE_URL!, { prepare: false, max: 10, idle_timeout: 20 })` bound with `drizzle(sql)`; the MySQL branch is `mysql.createPool({ uri: process.env.DATABASE_URL!, connectionLimit: 10 })` bound with `drizzle({ client: pool })`. Ten is a per-process number, not a per-request one. Every handler in the process shares those connections, an eleventh concurrent query waits on the pool instead of opening an eleventh backend, and the TCP, TLS, and auth handshake is paid once per connection rather than once per query. `idle_timeout: 20` is the other half of the setting.

Without it, one traffic burst leaves the process holding ten open backends for as long as it runs, which on a shared Postgres project is ten backends nothing else can have; twenty seconds of inactivity releases them and the next request reopens what it needs. The `mysql2` pool does its own idle recycling, so the MySQL branch expresses the same intent with just `connectionLimit`. `prepare: false` stays even here. Being long-lived does not change what is on the other end of `DATABASE_URL`: Neon's pooled `-pooler` host, PgBouncer in transaction mode, which can give each transaction a different backend, so a statement prepared on one is gone on the next.

The failure mode this target avoids is the quiet kind — a pool sized against the database's `max_connections` rather than against one process's real concurrency, or prepared statements left enabled against a transaction-mode pooler. Both are invisible in development and in a single-request test, and both surface only once several replicas are serving traffic at the same time.

Built for

Serve every request from one shared pool

The module-scope `postgres(..., { max: 10 })` call runs once per process and `drizzle(sql)` wraps that same handle, so all routes reuse ten warm connections instead of dialing per request.

Return idle connections to the database

`idle_timeout: 20` drops connections unused for twenty seconds, so a process that spiked and went quiet stops occupying backends that other replicas or services need.

Queue a spike instead of growing the pool

With `max: 10`, the eleventh simultaneous query blocks on the pool rather than opening another backend — the process's connection footprint stays a number you chose, not one traffic chose.

Stay correct behind Neon's pooler

`prepare: false` is kept despite the persistent process, because `DATABASE_URL` still resolves to the transaction-mode `-pooler` endpoint where prepared statements do not survive between transactions.

Run the same shape on MySQL

The `mysql2` branch reaches for that driver's native pool at `connectionLimit: 10` and binds it through `drizzle({ client: pool })`, matching the Postgres branch's sizing with the idiom MySQL actually uses.

Why Long-running Node (VPS / container), specifically

note

A long-running process holds a real pool (max ~10–20), unlike serverless's max:1-per-instance.

note

Still prepare: false on Neon's pooled (transaction-mode) endpoint; idle_timeout recycles idle connections.

What Long-running Node (VPS / container) pulls in

bun add postgres drizzle-orm
DATABASE_URLNeon POOLED (-pooler) connection string