← All use cases

Build your own Neon

Serverless Postgres that scales to zero — but yours. pg-fc gives every app, agent, or branch its own Postgres in its own Firecracker micro-VM. It boots on the first connect, stops when nobody is using it, and wakes on the next query. One pooler endpoint, as many databases as your hardware holds, on machines you own.

The database name is the provisioning API

pg-fc is two pieces: a Postgres guest image that boots straight into Postgres, and pg-vm-pool, a Postgres wire-protocol pooler listening on :6432. The database name in a client’s connection string picks the database. The pooler finds, restarts, or creates the VM behind it and splices the connection straight through.

01

Connect with a new name

A dbname the pooler has never seen gets a fresh micro-VM, its own data disk, and a clean initdb. No console, no provisioning call.

02

One VM per database

Each database runs in its own VM with its own disk. Postgres settings are regenerated at every boot from the VM’s actual RAM, vCPUs and disk.

03

Clients wait, not fail

When a VM is full, new clients wait at the pooler for a free backend slot instead of getting too many clients. A client that vanishes releases its slot.

# Start the pooler (listens on 127.0.0.1:6432)
target/release/pg-vm-pool

# The dbname selects the VM, creating it on first use
psql "host=127.0.0.1 port=6432 user=postgres dbname=tenant1"
-> VM pg-tenant1
psql "host=127.0.0.1 port=6432 user=postgres dbname=tenant2"
-> VM pg-tenant2

Idle databases cost disk, not RAM

A database that nobody is querying doesn’t need a running VM. pg-fc stops idle VMs and, if you turn them on, moves cold ones down through cheaper storage tiers. The next connect brings them back.

01

Warm

A running VM. The pooler splices the connection immediately.

02

Stopped

The VM is stopped and its data disk kept. A connect costs a VM start and Postgres startup — typically under a second to a few seconds.

03

Compacted and frozen

A trimmed, zstd-compressed disk image, or a pg_dump file, with the VM deleted. A connect restores onto a fresh VM.

04

Archived

An object in S3 or an S3-compatible bucket such as MinIO or R2. A connect downloads it, then restores as above.

  • Idle stop by default. With no tier settings at all, pg-fc only stops idle VMs: after 900 seconds with no connections, jittered ±15% per database. Every tier below warm is opt-in.
  • A two-speed reaper. Databases whose last bring-up was fast get a shorter 60-second idle timeout. When the host slows down, restarts stop counting as fast and the reaper backs off on its own.
  • No lost commits. The pooler runs CHECKPOINT before every idle stop.
  • Disks that grow. Data disks are thin-provisioned: the guest starts with a 2 GB filesystem and grows it online as the database grows. Turn on device growth and a data device is doubled at idle stop, up to a ceiling you set (100 GB by default).
  • Warm spares. Keep a number of pre-booted, initdb-complete spare VMs for new databases to claim, so a cold bring-up takes seconds instead of a full create and initdb.
  • Always-on when you need it. List latency-critical databases in PG_VM_POOL_KEEPALIVE_SCHEMAS and they are never idle-stopped or offloaded.

Credentials, replicas, and a dashboard

DB

Dedicated databases

Hand an app or a customer its own role and password. A dedicated credential can open only its own database and cannot create VMs. Revoking it keeps the data.

RE

Cross-host replication

Replicate a dedicated database continuously to a peer pg-fc node, using logical replication by default. Promote and detach are operator actions, not automatic failover.

UI

Dashboard and JSON API

An optional dashboard and JSON API inside the pooler: every VM’s state, host metrics, archives, events, log tails, webhook alerts, and runtime config changes without a restart.

# Provision a dedicated database (password is generated if omitted)
curl -u admin:$DASH_PASS -X POST http://127.0.0.1:34199/api/databases \
     -H 'content-type: application/json' -d '{"database":"acme"}'
201 {"database":"acme","username":"acme","password":"…","status":"provisioning",…}

# The client connects normally, over TLS
psql "host=pg.example.com port=6432 user=acme dbname=acme sslmode=require"

Set PG_VM_POOL_PASSWORD and the pooler challenges every client before it dials a VM. TLS terminates at the pooler, and certificate renewals need no restart.

A KVM box and four steps

  • Get a KVM-capable Linux server. Most modern Linux hardware is. Make sure your user can reach /dev/kvm and install Firecracker.
  • Install heyvm and run its daemon. The pooler drives VMs through the heyvm API on :34099.
  • Build the Postgres image. heyvm mvm build turns pg-fc’s Dockerfile into a bootable image named pg.
  • Build and run the pooler. cargo build --release, run it under supervisord or systemd, and connect on :6432.
# Build the guest image
heyvm mvm build --local-only -f Dockerfile.pg18 --name pg

# Run the heyvm API the pooler talks to
heyvm --api --port 34099

# First connect creates the first database
psql "host=127.0.0.1 port=6432 user=postgres dbname=tenant1"
heyvm list

The full walkthrough is in Build Your Own Serverless Postgres → Running the rest of Heyo Web Services alongside it? Start with the HWS installation docs →

Build your own cloud

A Postgres per app, agent, or branch that stops when idle and wakes on the next connect. Your hardware, your data, your rules.