⏱️ Reading time: 13 min

Most projects that promise to “rewrite X in Rust” never go beyond a pretty demo on GitHub. pgrust breaks that pattern. While attempting to rewrite PostgreSQL in Rust, its author subjected the code to so much testing that he ended up finding real bugs inside the original Postgres, the one running in production worldwide.

📑 En este artículo
  1. TL;DR
  2. What is pgrust?
  3. Why rewriting PostgreSQL in Rust is a real bet
  4. How pgrust uncovered real bugs in Postgres
  5. Practical examples: what differential testing looks like
  6. Real-world use cases
  7. Comparison: pgrust and other attempts to reinvent Postgres
  8. Common mistakes when attempting a rewrite like pgrust
  9. Going deeper: why a second implementation uncovers bugs in the first
  10. Frequently Asked Questions
    1. Is pgrust ready to replace PostgreSQL in production?
    2. Who develops pgrust?
    3. What bugs did pgrust find in Postgres?
    4. Why would someone rewrite PostgreSQL in Rust instead of patching the original?
    5. Does reimplementing PostgreSQL in Rust improve memory safety?
    6. What happens if pgrust never becomes a complete Postgres replacement?
  11. References

This isn’t another “rewrite it in Rust” meme. It’s proof that, when testing is aggressive and honest, even an unfinished personal project can improve the software it imitates. Here’s what pgrust is, what errors it uncovered in Postgres, and what it means as a case study in safely rewriting mature software.

TL;DR

  • pgrust is a personal project by Michael Malis aiming to rewrite PostgreSQL in Rust, focused on performance.
  • Its aggressive testing has already found five real bugs in Postgres, including failures in SP-GiST and JSONPath.
  • pgrust’s optimizations could make their way into Postgres or ClickHouse even if the rewrite never reaches production.
  • Dan Luu documented the bugs at danluu.com/ambitious as an example of rigorous testing, with no AI filler.
  • Most of today’s viral rewrites are AI-generated smoke: pgrust stands out for testing seriously.

What is pgrust?

pgrust is a personal project by engineer Michael Malis that aims to rewrite PostgreSQL in Rust while maintaining protocol and on-disk compatibility with the original Postgres written in C. It’s not a cosmetic fork: it reimplements the storage engine, the query planner, and a good portion of the native data types.

The stated goal isn’t architectural purity, but performance. As Dan Luu reports, Malis is betting that an engine written in Rust, with better memory control and less indirection than Postgres’s classic C, can run the same queries faster without sacrificing compatibility with the existing ecosystem of clients, drivers, and extensions already built for PostgreSQL.

But what makes pgrust relevant isn’t the promise of speed, still without any public comparable data. It’s the level of testing Malis applied while building the replacement, so thorough that the very process of validating that pgrust behaved the same as Postgres ended up revealing errors that had been hiding in the original code for a long time.

PostgreSQL was born in the nineties, and its core is still written in C. Foto de Thomas Tastet en Unsplash

Why rewriting PostgreSQL in Rust is a real bet

A new “rewrite it in Rust” shows up on Hacker News and Reddit almost every week. Most are weekend demos: they implement the easiest 5% of a complex program, publish a favorable benchmark, and disappear. That’s why the automatic reaction to an announcement like this is skepticism, and in 2026 that skepticism is more justified than ever. There’s no shortage of AI-generated code with no real tests behind it.

pgrust’s case is different because Malis didn’t stop at the engine’s “hello world.” To make sure his rewrite returns exactly the same results as Postgres, he built a verification process that runs the same queries against both engines and compares the outputs. That discipline, known in software engineering as differential testing, is expensive to do well, and it’s the reason most rewrites never reach that level.

💭 Key point: differential testing doesn’t just validate the new code, it also exposes latent bugs in the old code, because it forces an unambiguous definition of the correct behavior for every edge case.

How pgrust uncovered real bugs in Postgres

As Malis built the PostgreSQL reimplementation, the process of comparing result against result kept turning up discrepancies. Each discrepancy was one of two things: a bug in pgrust, or a bug that already existed in the original Postgres and that nobody had detected. According to Dan Luu’s count, at least five of those discrepancies turned out to be real failures in Postgres itself.

flowchart TD
A["Same SQL query"] --> B["Original Postgres in C"]
A --> C["pgrust in Rust"]
B --> D["Result A"]
C --> E["Result B"]
D --> F["Byte-by-byte comparator"]
E --> F
F --> G["Difference found"]
G --> H["Bug reported to Postgres"]
Affected subsystemBug typeWhy it matters
SP-GiSTNumeric errorCould cause valid operations on this indexing method to fail
JSONPathCorrupted format cacheReturned incorrect results in jsonb queries with JSONPath paths
pgcryptoInconsistent stateAn encryption operation could leave the module in a state that broke subsequent calls
Text search dictionary loaderSeveral memory bugsCould corrupt memory when loading full-text search dictionaries (ispell, synonyms)
money typeNumeric overflowThe monetary type could overflow beyond its documented range

None of these bugs are exotic. All of them affect functions that any production application could be using today without knowing it. Finding a failure in SP-GiST matters because that indexing method backs spatial and range search types, and breaking JSONPath matters because jsonb has been, since Postgres 12, the standard way to store semi-structured documents inside a relational database.

pgrust isn’t free of bugs either, and Malis makes that clear: the project itself is still in development. But that’s not the point. Even if pgrust never replaces Postgres in production, the process of trying already left a lasting improvement in the software everyone uses, because the reported bugs get fixed in the real Postgres, not in a parallel copy that nobody runs.

Practical examples: what differential testing looks like

You don’t need pgrust’s code to understand the technique. Differential testing compares, query by query, what two implementations that should behave the same way return. Here’s a simplified example in Python using psycopg2, comparing any two connections that speak the PostgreSQL protocol:

import psycopg2

def run(dsn, query):
    with psycopg2.connect(dsn) as conn:
        with conn.cursor() as cur:
            cur.execute(query)
            return cur.fetchall()

query = "SELECT '1234567.89'::money, upper('hola');"

resultado_a = run("dbname=postgres_original", query)
resultado_b = run("dbname=postgres_candidato", query)

if resultado_a != resultado_b:
    print(f"DIVERGENCE in: {query}")
    print(f"  original:  {resultado_a}")
    print(f"  candidate: {resultado_b}")
else:
    print("Results match")

Running this script against two identical Postgres instances, the expected output is Results match. The technique becomes interesting when one of the two connections points to a rewrite like pgrust: there, any printed DIVERGENCE is a clue to a bug, whether in the rewrite or, as happened several times with pgrust, in Postgres itself.

sequenceDiagram
participant Client
participant Postgres as "Original Postgres"
participant Pgrust as "pgrust"
Client->>Postgres: executes SQL query
Client->>Pgrust: executes the same query
Postgres-->>Client: returns result A
Pgrust-->>Client: returns result B
Note over Client: compares A and B byte by byte

To confirm that a divergence is real and not a connection artifact, repeat the query with EXPLAIN (ANALYZE, BUFFERS) on both connections. If the execution plans differ, the cause might be in the configuration rather than a bug in the engine. Scaling this technique usually means generating random queries with a fuzzer and letting it run for hours, accumulating edge cases that no hand-written test would cover.

Real-world use cases

The idea behind porting Postgres to Rust didn’t start with pgrust. Rust already has a track record of replacing classic Unix tools: ripgrep replaced grep in the daily workflow of many developers, and the uutils project rewrites the entire GNU coreutils toolset in Rust. In databases, Neon separated Postgres’s storage into its own layer written in Rust to enable instant database branching, and OrioleDB rewrote Postgres’s storage engine as an extension, though it stayed in C.

What these projects share with pgrust is that none of them promises to replace the original overnight. They compete on a subset of the problem, under real workloads, and let time, and testing, decide whether the rewrite holds up to the comparison.

Comparison: pgrust and other attempts to reinvent Postgres

The table compares pgrust’s scope with other well-known projects in the same space:

ProjectWhat it rewritesLanguageMain goal
pgrustThe complete PostgreSQL engineRustPerformance with protocol compatibility
OrioleDBThe storage engine, as an extensionCBetter MVCC handling and less bloat
NeonThe storage layer, separated from computeRustServerless databases with branching
uutils coreutilsThe GNU coreutils toolsRustMemory-safe replacement for Unix utilities

N-version programming has been used since the 1970s in systems where a bug can’t be tolerated, like flight control. Foto de CDC en Unsplash

Common mistakes when attempting a rewrite like pgrust

The most common mistake is declaring success with a microbenchmark. Running a single simple query faster than the original proves nothing about a database engine. What matters is behavior under mixed workloads, with indexes, concurrent transactions, and real data. pgrust avoids this mistake by relying on comparing results, not just timings.

Another mistake is underestimating the compatibility surface. Postgres isn’t just the SQL engine: it’s also the network protocol spoken by psql and every driver, the binary format of its data types, and dozens of third-party extensions. A rewrite that ignores any of those contracts breaks applications silently, long after it’s released.

The third mistake, less technical, is judging every rewrite attempt by the category average. Most “I rewrote X in Rust” projects circulating today are, in effect, little more than AI-assisted demos with no real testing behind them. But dismissing pgrust just for belonging to that category ignores the concrete evidence of the five bugs reported and fixed in Postgres.

⚠️ Watch out: a rewrite finding bugs in the original doesn’t prove the rewrite itself is production-ready. pgrust is still a personal project in development, not a certified Postgres replacement.

Going deeper: why a second implementation uncovers bugs in the first

The phenomenon behind pgrust has a name in software engineering: N-version programming, a technique from the 1970s that involves building several independent implementations of the same specification and comparing them for divergences. The logic is simple. It’s unlikely that two different implementations make exactly the same mistake on the same edge case, so any difference is suspicious.

Rust brings something that alternative implementations in C don’t get for free. Its borrow checker prevents, at compile time, entire classes of memory errors like use-after-free or buffer overflows. That doesn’t eliminate logic bugs, like the money type overflow, which is a range error rather than a memory one, but it does reduce the class of bugs pgrust can introduce while rebuilding Postgres’s logic.

fn main() {
    let datos = vec![1, 2, 3];
    let referencia = &datos[0];
    datos.push(4);
    println!("{}", referencia);
}

This program doesn’t compile in Rust. The compiler rejects the push because it keeps a reference to datos alive. The actual output when compiling it with rustc is an error like cannot borrow `datos` as mutable because it is also borrowed as immutable, caught before executing a single line. In C, the equivalent would compile without warnings and fail, or not, only at runtime.

There’s an important nuance here. Finding a bug with differential testing is easier than fixing it properly. Every failure reported to Postgres goes through its own review process, with its own discussion about whether the documented behavior matches what the code actually does. Several of the fixes for the bugs pgrust uncovered required that discussion before being accepted, because the problem wasn’t just that the code was wrong, but deciding what the documentation says should happen in that case.

There’s a broader context behind this case, which Dan Luu raises in the same article: current tools, including AI coding assistance, lowered the cost of attempting ambitious projects that used to take years so much that a developer can now reach a working version in hours. But that same ease multiplied the number of low-quality projects presented as serious rewrites. What sets pgrust apart from the rest is the aggressive testing behind it. That discipline is what ended up finding cracks in Postgres itself.

Your next step: take any small PostgreSQL extension in C that you have installed, spin up two databases with the same version, run the same battery of queries against both with a script like the one above, and compare the results byte by byte before trusting that a configuration change is harmless.

📬 Get new articles by email

We only email about big articles (1-2 a month).

Frequently Asked Questions

Is pgrust ready to replace PostgreSQL in production?

No. It’s a personal project in development, without the maturity or extension ecosystem that Postgres has after nearly three decades in production. Its value today lies in the testing process, not in being a ready-to-use replacement.

Who develops pgrust?

Engineer Michael Malis, who shares the project’s progress informally. Dan Luu documented the work on his blog after verifying the bug reports it generated.

What bugs did pgrust find in Postgres?

At least five: a numeric error in SP-GiST, a corrupted format cache that broke JSONPath, an inconsistent state in pgcrypto, several memory bugs in the full-text search dictionary loader, and an overflow in the money type.

Why would someone rewrite PostgreSQL in Rust instead of patching the original?

Because some performance optimizations require deep structural changes to the storage engine, which are hard to introduce incrementally into a thirty-year-old codebase without breaking compatibility. Rewriting from scratch, with differential testing against the original, allows testing those changes without risking production.

Does reimplementing PostgreSQL in Rust improve memory safety?

In theory yes, because Rust eliminates at compile time classes of memory bugs that in C depend on the programmer’s discipline. But that doesn’t prevent logic bugs like the range overflow pgrust found in the money type, which isn’t a memory bug.

What happens if pgrust never becomes a complete Postgres replacement?

It still leaves value behind: every real bug it uncovered has already been fixed or is being fixed in the Postgres everyone uses, and any performance optimizations it demonstrates could be adapted into Postgres or other engines like ClickHouse.

References

📱 Enjoying this content? Follow @programacion on Telegram for daily tech content in Spanish: quick summaries, fresh content every day.

Featured image: Foto de CDC en Unsplash

Did it work for you? Got a different error? Say so below: questions get answered and help the next reader.

Leave a comment
Categories: Tech NewsTutorials

Andrés Morales

Developer and AI researcher. Writes about language models, frameworks, developer tooling, and open source releases. Covers ML papers, the tech startup ecosystem, and programming trends.

0 Comments

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *

You can include code inside <code>…</code> or, for several lines, <pre><code>…</code></pre>.

This site uses Akismet to reduce spam. Learn how your comment data is processed.