Pool with idleTimeoutMillis: 0 or missing (long-lived process)
Part of the Idle compute cost check · fix arrives as a pull request
What it is
A connection pool in a long-lived process has idleTimeoutMillis set to 0 or left unset, so idle connections are held open indefinitely.
Why it matters
An open connection prevents the compute endpoint from suspending. A single idle pool connection is enough to keep the database billing all night for zero queries.
What it looks like
import { Pool } from 'pg';
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
idleTimeoutMillis: 0, // “never close idle connections”
});In node-postgres, 0 disables idle reaping entirely. The default is 10 seconds — so this is always a deliberate line, usually copied from a thread about serverless cold starts, and it costs real money on Neon.
Why one idle connection keeps the meter running
Neon bills for compute time and suspends a compute after five minutes with no activity — that scale-to-zero is most of the point of the platform for small apps. But suspension requires zero open connections. A long-lived process — a container, a VM, a background worker — whose pool never releases its idle connection pins the endpoint awake around the clock: roughly 720 compute-hours a month billed against zero queries.
The other pool that does this quietly
Knex is the common second offender — its default pool is { min: 2, max: 10 }, and a non-zero min holds two connections open forever regardless of any idle timeout:
// knex — let the pool drain when idle
const db = knex({
client: 'pg',
connection: process.env.DATABASE_URL,
pool: { min: 0, max: 10, idleTimeoutMillis: 30_000 },
});Fix it manually
Let idle connections close, keep the floor at zero, and give one-shot scripts permission to exit:
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
idleTimeoutMillis: 30_000, // release after 30s quiet
min: 0, // hold nothing open when idle
allowExitOnIdle: true, // scripts/workers: let the process end
});Reconnecting after a suspend costs one cold start (typically well under a second on Neon); paying that occasionally is the trade the platform is built around. In serverless functions the calculus is different — there, use the -pooler connection string or the @neondatabase/serverless driver rather than tuning a per-instance pool.
How lumioguard fixes it
The scan pairs every pool configuration in the repo with what your Neon branch actually does at night — an endpoint that never suspends is the confirming signal. The fix arrives as a pull request with the pool settings above, sized to the process it found them in.
Run them all on your app
Connect your repo and your live services with read-only scopes. The first scan is free, and nothing changes without your approval.