Neon Cost Performance Stability

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.