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 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
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.
`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.
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.
`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.
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
A long-running process holds a real pool (max ~10–20), unlike serverless's max:1-per-instance.
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-ormDATABASE_URLNeon POOLED (-pooler) connection string