2026.07.07 · 8 min read · postgres

The 400ms warm tier: parking a database without breaking single-writer

The pod exists, the container runs, and Postgres hasn't started — it's blocked polling a gate on the gateway via bash /dev/tcp. Opening the gate IS the wake.

Ahmed El Banna
Ahmed El Banna
Technical Leader · Full-Stack Engineer

Part 5, closing the scale-to-zero Postgres series.

By part 1's measurements, a cold database wake costs ~2.5 seconds — and almost none of it is the database. Neon's stateless compute attaches in ~150ms; the rest is kubelet sandbox setup, container starts, and probe propagation. You can't tune away pod creation. But you can stop creating the pod.

The gated pod

The warm tier is a second compute Deployment whose pod always exists but whose entrypoint blocks before starting Postgres:

# entrypoint-warm.sh — parked until the gateway says go
until (exec 3<>"/dev/tcp/${GATE_HOST}/${GATE_PORT}") 2>/dev/null; do
  sleep 0.2
done
exec /compute-files/entrypoint.sh   # the normal attach path

Two details I like about this. First, the polling target is a gate port on the gateway itself — a net.Listener the gateway opens and closes in-process. Gate open means the listener accepts (each accept releases one waiter); gate closed means the listener doesn't exist. No ConfigMap propagation delays (a kubelet sync can take a minute — that's a wake path, so it's disqualified), no kubectl exec (the review that killed the prototype's shell harness was right to), no sidecars. Second, the poll uses bash's /dev/tcp because the stock compute image ships no curl — the mechanism bends to the image, not the other way around.

Waking is opening the gate: no scheduling, no image pull, no container start. Just the ~150ms attach plus one poll interval. Measured: 413ms p50, 206ms best, every percentile under a second. Re-parking is equally clean: close the gate and delete the pod — the Deployment respawns it, and the fresh replica blocks on the gate again. Parked.

The invariant that makes this dangerous

Here's the problem hiding in the design: the warm pod and the cold Deployment's pod attach to the same timeline. Neon's architecture is strictly single-writer per timeline — two attached primaries is not "degraded," it's the one corruption class the whole storage model exists to prevent.

So the gate has a guard. Before opening, the gateway asks the Kubernetes API two questions and requires both answers to be zero: the cold Deployment's replica count, and — separately — the count of its pods including Terminating ones. That second clause is earned scar tissue: a draining pod still holds the timeline for its grace period, and "replicas: 0" says nothing about it. Any API error refuses the gate — when unsure whether another writer exists, the answer is no.

The test I care most about in the entire repository is the negative one:

With the cold compute running, the gate must refuse to open.

It's verified twice — as a Go table test with a fake API, and live in the drill, which deliberately scales the cold compute up and asserts the warm connection fails. Positive tests prove features work; this negative test proves the feature can't destroy the database. Only one of those keeps you employed.

Honest pricing, honest naming

A parked pod reserves its requests around the clock — 256Mi of RAM and a CPU sliver, per database, forever. So the docs refuse to call it scale-to-zero; it's a warm-RAM tier, opt-in per app, and it ships disabled (replicas: 0) so the default posture stays truly zero. The tier table an app team reads is two columns: cold-zero (wake ~2.5s, idle cost 0) vs warm (wake ~0.4s, idle cost one parked pod). Nothing in the application changes either way — same DSN, same driver; the only observable difference is the first connection after idle.

That honesty had a second payoff I didn't anticipate: the warm tier's existence is what settled the foundation debate in part 3. Pod-recreation architectures (hibernation) bottom out at 4–5s; a parked stateless compute bottoms out at the attach. The tier isn't a bonus feature — it's the structural argument.

Series wrap: what five parts add up to

Everything is drill-measured with receipts in the repo's BENCHMARKS.mdgetknext-dev/scale-zero-pg, built on Neon's open source. The platform now pairs with knext so the app and its database sleep and wake together — which was the point all along.