minipg: PostgreSQL as a single executable

Jeff Lindsay, h.d.a.

About

minipg is PostgreSQL as one binary, with nothing to install or configure. A .pgdb directory is the database: its data, config, credentials, and Postgres version all live inside it, and minipg app.pgdb opens a psql shell on it. A server starts when a command needs one and stops on its own when it's idle.

minipg embeds Docker Hub's postgres:18-alpine image and runs it with h9, used as a Zig library. h9's Linux personality runs Alpine's own Postgres binaries directly on the host's hypervisor, with h9's Plan 9 kernel answering their system calls. There's no Linux kernel to boot, no VM image, and no Docker.

Demo

Below is minipg in your browser: a shell with minipg on its path, running Postgres 18 for 386 Linux on h9's browser host, which is h9 built for wasm32-wasi with v86, in a Web Worker. Try minipg app.pgdb for psql, minipg app.pgdb "select version()", minipg status app.pgdb, or minipg dump app.pgdb. The first command starts the server, which takes about 15 seconds here.

The demo downloads about 35 MB. It needs JavaScript Promise Integration, which Chrome and Edge have from version 137; other browsers are getting it. It can also be opened on its own page.

The demo runs minipg's Linux build, which runs inside the Postgres image itself. It starts Postgres as ordinary processes and serves on a unix socket, since a page has no TCP. New databases come from a template cluster made at build time, because initdb takes half a minute on v86.

Using It

minipg app.pgdb                     # psql shell (creates app.pgdb if missing)
minipg app.pgdb "select 1"          # one statement
minipg url app.pgdb                 # postgres://postgres:...@127.0.0.1:54321/app
minipg serve app.pgdb               # an explicit foreground server
minipg run app.pgdb -- npm start    # your app, with DATABASE_URL set
minipg dump app.pgdb > dump.sql     # and minipg restore app.pgdb dump.sql

A .pgdb holds minipg.toml (settings and the generated superuser password) and pgdata/, Postgres's data directory as plain files. A stopped one can be copied like any directory. New clusters use Postgres's builtin C.UTF-8 locale, which sorts the same on every platform.

In CI, the Linux binary is static and needs no privileges or devices: without /dev/kvm, h9 runs Postgres on its native backend. A test job can be as small as:

minipg init test.pgdb
minipg run test.pgdb -- go test ./...

The README lists every command, and the manual is the full guide.

How It Works

Exactly one process runs Postgres for a .pgdb, enforced by a lock. It holds the server's h9 machine, whose Linux root is the unpacked image and whose writable working directory is the .pgdb. The image's docker-entrypoint.sh initializes the cluster on first start. Commands never host Postgres themselves. If no server is running, they start one in the background and use it. psql, pg_dump, and the other tools each run in their own short-lived h9 machine (about 90 ms to start) over the same root.

Linux x86_64KVM, or h9's native backend without it (Linux 5.11 or later)
Linux arm64KVM
macOS (Apple Silicon)Hypervisor.framework
The browserh9's web host, v86, and minipg's Linux build

Source Code

The source is on GitHub, under the MIT license. Building needs Zig 0.16, plus curl, jq, tar, and xz for the root:

git clone --recursive https://github.com/progrium/minipg
cd minipg
make build         # pulls the root for this host's arch, builds ./minipg
make root ARCH=386
make web           # this page's demo, in .zig-out/web

Warning!

minipg is early, and h9's Linux personality is young. On h9's native backend, Postgres is about 2x slower than native for one client, and slower under load. Don't trust it with data you can't recreate yet.

Please report bugs and send questions through GitHub issues.