malisper/pgrust(新しいタブで開きます)
主要言語: Rust
Postgres rewritten in Rust, now faster than Postgres and Clickhouse
- star 数
- 5,683
- watcher 数
- 46
- fork 数
- 218
- issue 数
- 56
- 最終更新
- 2026/10/27
主要言語: Rust
Postgres rewritten in Rust, now faster than Postgres and Clickhouse
A Rust rewrite of Postgres.
New: Video of Michael's talk at PlanetScale on pgrust — and the slides.
How AI Changes the Economics of JIT Compilers
v0.4-beta is out: the release post and what's new.
pgrust is a re-implementation of Postgres meant to show what Postgres would look like if it was built in 2026. It is wire compatible and even SQL dialect compatible with Postgres.
Every line is Rust, written to match the behavior of the C implementation. Rust makes it easy to re-architect several core Postgres pieces. pgrust has:
and many other really awesome pieces. The scheduler and the memory manager go after two of the four horsemen behind thousands of Postgres outages.
In your browser: https://pgrust.com, a full pgrust server compiled to WebAssembly, no install.
On your machine: download a release tarball from
https://pgrust.com/downloads/v0.4-beta/. Each one is self-contained: it
carries pgrust's own bin/postgres, bin/initdb and bin/psql plus the
share files they read, so you do not need a PostgreSQL install. The Linux
binaries need glibc 2.34 or newer (Debian 12, Ubuntu 22.04, RHEL/Rocky 9 and
later); the macOS binaries need macOS 11 or newer.
| Tarball | Runs on |
|---|---|
pgrust-0.4-beta-linux-x86_64.tar.gz |
any x86-64 CPU |
pgrust-0.4-beta-linux-aarch64.tar.gz |
any 64-bit Arm CPU |
pgrust-0.4-beta-linux-x86_64-znver3.tar.gz |
tuned for AMD Zen 3 and newer |
pgrust-0.4-beta-linux-aarch64-neoverse-v2.tar.gz |
tuned for Neoverse-V2 (AWS Graviton4, NVIDIA Grace) |
pgrust-0.4-beta-macos-arm64.tar.gz |
macOS on Apple Silicon |
pgrust-0.4-beta-macos-x86_64.tar.gz |
macOS on Intel |
pgrust-0.4-beta-macos-universal.tar.gz |
macOS, either (both architectures in one binary) |
The Linux builds are profile-guided optimized. The tuned builds use
instructions only those CPUs (and newer ones) have; when in doubt, take the
generic build. Every tarball has a .sha256 file next to it, and
MANIFEST.txt lists
them all.
# Pick your build: linux-x86_64, linux-aarch64, linux-x86_64-znver3 or # linux-aarch64-neoverse-v2 (see the table above). PLATFORM=linux-x86_64 # Download pgrust, verify the checksum and unpack it. curl -LO "https://pgrust.com/downloads/v0.4-beta/pgrust-0.4-beta-$PLATFORM.tar.gz" curl -LO "https://pgrust.com/downloads/v0.4-beta/pgrust-0.4-beta-$PLATFORM.tar.gz.sha256" sha256sum -c "pgrust-0.4-beta-$PLATFORM.tar.gz.sha256" tar xzf "pgrust-0.4-beta-$PLATFORM.tar.gz" cd pgrust-0.4-beta-linux-*/ # Create a data directory with pgrust's initdb. bin/initdb -D /tmp/pgrust-data --no-locale --encoding UTF8 -U postgres # Start the server. It runs in the foreground and logs to this terminal. ulimit -s 65520 RUST_MIN_STACK=33554432 bin/postgres \ -D /tmp/pgrust-data \ -k /tmp -p 5432 \ -c listen_addresses= \ -c io_method=sync \ -c max_stack_depth=60000
Leave the server running and connect from a second terminal, in the same directory:
bin/psql -h /tmp -p 5432 -U postgres -c "select version()"You should see PostgreSQL 18.6 (pgrust 0.4-beta, build <commit>) on ...,
where <commit> is the short commit the binary was built from.
bin/postgres --version prints pgrust 0.4-beta (PostgreSQL 18.6 compatible).
The prebuilt image on Docker Hub,
malisper/pgrust, is a drop-in
replacement for the official postgres image: same env vars
(POSTGRES_PASSWORD, POSTGRES_USER, POSTGRES_DB, PGDATA, ...), same
/docker-entrypoint-initdb.d init scripts, same data volume at
/var/lib/postgresql/data. It carries the same postgres and initdb
binaries as the Linux release tarballs above, and initializes the cluster with
pgrust's own initdb; the only C PostgreSQL component in the image is psql
for the init scripts. malisper/pgrust:v0.4-beta is multi-arch (amd64 +
arm64); v0.4-beta-amd64 and v0.4-beta-arm64 pin one architecture.
docker run -d --name pgrust -e POSTGRES_PASSWORD=secret -p 5432:5432 malisper/pgrust:v0.4-beta
Then connect, with your own psql or the one in the image:
psql -h localhost -p 5432 -U postgres
docker exec -it pgrust psql -U postgresmalisper/pgrust:latest still points at v0.3; use the v0.4-beta tag to get
this release. A data volume written by v0.3 holding columnar tables needs the
dump and restore described under
Stopping, restarting, cleaning up.
# Pick your build: macos-arm64 (Apple Silicon), macos-x86_64 (Intel) or # macos-universal (both). PLATFORM=macos-arm64 # Download pgrust, verify the checksum and unpack it. Download with curl: curl # does not set the quarantine flag a browser download gets, so Gatekeeper stays # out of the way (see the note below). curl -LO "https://pgrust.com/downloads/v0.4-beta/pgrust-0.4-beta-$PLATFORM.tar.gz" curl -LO "https://pgrust.com/downloads/v0.4-beta/pgrust-0.4-beta-$PLATFORM.tar.gz.sha256" shasum -a 256 -c "pgrust-0.4-beta-$PLATFORM.tar.gz.sha256" tar xzf "pgrust-0.4-beta-$PLATFORM.tar.gz" cd "pgrust-0.4-beta-$PLATFORM" # Create a data directory with pgrust's initdb. bin/initdb -D /tmp/pgrust-data --no-locale --encoding UTF8 -U postgres # Start the server. It runs in the foreground and logs to this terminal. ulimit -s 65520 RUST_MIN_STACK=33554432 bin/postgres \ -D /tmp/pgrust-data \ -k /tmp -p 5432 \ -c listen_addresses= \ -c io_method=sync \ -c max_stack_depth=60000
Leave the server running and connect from a second terminal, in the same directory:
bin/psql -h /tmp -p 5432 -U postgres -c "select version()"A note on Gatekeeper: the macOS binaries are signed ad hoc, not notarized
by Apple. Downloaded with curl as above, they are never quarantined and none
of this comes up. If you download with a browser instead, macOS refuses to run
them with "Apple could not verify ... is free of malware". Clear the flag with
xattr -dr com.apple.quarantine pgrust-0.4-beta-$PLATFORM, or approve each
binary under System Settings > Privacy & Security > "Open Anyway".
Columnar storage (pgrcolumnar) is a table access method. Register it once in
each database, then create tables with USING pgrcolumnar:
CREATE ACCESS METHOD pgrcolumnar TYPE TABLE HANDLER heap_tableam_handler; CREATE TABLE events (id bigint, kind text, val double precision, at timestamp) USING pgrcolumnar;
kill -INT <pid>. That
is Postgres' fast shutdown and it is safe.rm -rf /tmp/pgrust-data.
This deletes all data in it.FATAL: lock file "/tmp/.s.PGSQL.5432.lock" already exists, another server, most likely an existing Postgres install,
is already using port 5432. Start pgrust on a different port with -p 5433
and connect with psql -h /tmp -p 5433 -U postgres. Whenever a regular
Postgres is running on the same machine, check select version() after
connecting; it is easy to silently connect to the wrong server and wonder
why nothing behaves like pgrust.could not open directory "/usr/local/pgsql/share/timezone", the server cannot find its share files.
It reads them from the share directory beside the binary, so run
bin/postgres from the unpacked tarball as is, without moving the binary
away from bin/share. PGRUST_PGSHAREDIR and PGRUST_TZDIR point it
elsewhere.USING pgrcolumnar) are refused with an
error saying the table is in the v0.3.x columnar format. Dump them with the
v0.3 binary (pg_dump) and restore them into v0.4-beta.We don't recommend running pgrust in production (yet), but we are successfully running it ourselves internally. Keep Postgres as the source of truth for data you can't afford to lose.
pgrust still has a lot of bugs. Our #1 priority right now is testing and reliability.
If you need production ready Postgres today, use Postgres.
PostgreSQL extensions don't work out of the box: there is no stable extension ABI in pgrust yet. But pgrust ships a large number of them, including pgvector, pg_cron, pg_stat_statements, pg_trgm, hstore, pgcrypto, postgres_fdw and most of contrib. PL/Python, PL/Perl and PL/Tcl are not supported yet.
Measured on c8g.4xlarge (AWS Graviton4), pgrust with pgrcolumnar, its
builtin columnar layout, runs ClickBench's analytical queries up to 1,600x
faster than PostgreSQL (per query, cold runs, against PostgreSQL's published
results on the same instance type).
For a code-level walkthrough of one part of that speedup, read how batching, operator fusion, and SIMD speed up the query engine.
The most common question we get about pgrust is: how can anyone trust it? Passing a test suite doesn't mean our code is correct. Getting to the point where people can trust pgrust is our number one priority today.
To achieve that goal, we're taking several different approaches:
proofs/USER_FACING_FUNCTIONS.tsv.pgrust uses unsafe code, but only for the specific things that need it. Postgres represents every internal value as a Datum, an untyped 8 byte value, and Rust has no safe equivalent, so the code that packs and unpacks internal values is unsafe. The same goes for the places where pgrust must match Postgres' memory layouts byte for byte.
If there are particular unsafes that are not necessary and removing them would not have an impact on performance, let us know, as we would love to remove more unsafes.
You need the Rust toolchain (any rustup install works;
rust-toolchain.toml pins the build to Rust 1.96.0 and rustup fetches it
automatically) and the RE2 regex library:
sudo apt-get install -y build-essential pkg-config libre2-devbrew install re2 pkg-configcargo build --release --locked -p main_main -p initdb
select version() names the build: a build in a git checkout prints its short
commit (PostgreSQL 18.6 (pgrust 0.4-beta, build 1a2b3c4) on ...); set
PGRUST_BUILD_ID at build time to choose the id, or build outside git for none.
postgres --version prints pgrust 0.4-beta (PostgreSQL 18.6 compatible);
postgres -V prints postgres (PostgreSQL) 18.6, the line PostgreSQL's own
pg_ctl, initdb and pg_upgrade check.
The server binary lands at target/release/postgres, pgrust's initdb beside
it, and the share tree it needs (postgres.bki, the setup SQL, timezone,
timezonesets, tsearch data, extension files) is staged at target/release/share/. No C
PostgreSQL is involved in creating or running a cluster:
target/release/initdb -D /tmp/pgrust-data --no-locale --encoding UTF8 -U postgres
ulimit -s 65520
RUST_MIN_STACK=33554432 target/release/postgres -D /tmp/pgrust-data \
-k /tmp -p 5432 -c listen_addresses= -c io_method=sync -c max_stack_depth=60000The time zone database is PostgreSQL 18.6's own compiled tzdata, read from
share/timezone beside the binary (never the host zoneinfo, like C built
without --with-system-tzdata). To use the system zoneinfo instead, build with
PGRUST_SYSTEM_TZDATA=/usr/share/zoneinfo (C's --with-system-tzdata);
PGRUST_TZDIR and PGRUST_PGSHAREDIR remain runtime overrides, not
requirements. A data directory made
by stock PostgreSQL 18 initdb still works too (same on-disk format).
Release builds refuse to compile without RE2 on purpose: a
build with only the fallback regex engine is drastically slower on regex
heavy workloads. The binaries we publish additionally use --profile dist,
which turns on fat LTO; it produces a faster binary but takes much longer to
compile.
pgrcolumnar stores compressed, immutable parts
with zone maps, delete vectors and background compaction. Reads see
PostgreSQL MVCC snapshots, and writes are transactional: they roll back
with the transaction. Small inserts land in a row-store front that is
folded into columnar parts in the background, and UPDATE and DELETE mark
rows in delete vectors instead of rewriting parts (ON CONFLICT and MERGE
are not supported on columnar tables yet). Columnar tables take
non-unique B-tree, hash, GiST, SP-GiST and GIN indexes, are written to
WAL, so they survive crashes and replicate to standbys, and support row
locks and a sorted_by table option.ANALYZE collects statistics on the keys and values
inside jsonb columns, and the planner uses them for ->, ->>, #>,
#>> and ?, ?|, ?&, so it estimates jsonb filters instead of
guessing. On by default (pgrust.jsonb_path_stats).full is the default
(also spelled on) and stores match counts too. rows keeps row
selections and per-dictionary-code filter tables without counts;
granule keeps only empty-granule verdicts; off disables predicate
reuse. pgrust.dict_filter_cache and pgrust.zone_store turn off the
per-dictionary-code filter tables and the zone-map result store on their
own. Sizing feedback, data caches, and startup prewarm have separate
controls.initdb, and pg_cron 1.6 is included.v0.4-beta is a beta: it shows what is coming in v0.4 while we finish stabilizing the rest.
Up to v0.3 we developed pgrust privately and published it in large monthly releases. Starting with v0.4-beta, development happens in this repository: features, optimizations and bug fixes are pushed here as soon as they are ready, instead of being held back for the next release.
Executor
Parallelism
Storage
pgrcolumnar, a column-oriented format with dictionary encoding and
several other compression schemes, WAL-logged.fsync. A worker releases its locks after calling fsync but
before it completes. This is safe because the query is not acknowledged,
and none of its effects are observable, until the fsync finishes.Other
Next we're working on testing and battle testing pgrust and making it so people can trust pgrust with their data.
Beyond that we want to add:
We are not actively accepting pull requests right now. If you want to help out with the project, reach out on Discord.
Please do still open an issue if something breaks, if setup is confusing, or if there is a Postgres behavior you want matched.
pgrust is licensed under AGPL-3.0. Portions derived from
PostgreSQL remain under the PostgreSQL License. The JIT's code generator
(crates/tpde/) is ported from TPDE (Apache-2.0 WITH LLVM-exception) and
Fadec and Disarm (BSD-3-Clause). See NOTICE.
Acknowledgements: the research and other systems whose ideas pgrust uses are
credited in ACKNOWLEDGEMENTS.md.