Performance Differences Between pgrust and PostgreSQL: A Deep Dive into the Rust Rewrite

pgrust achieves approximately 50% faster transaction processing and up to 300× faster analytical query performance compared to PostgreSQL 18.3 by replacing the process-per-connection model with threads, leveraging Rust's zero-cost abstractions, and utilizing thread-local storage for backend state.

pgrust is a Rust-rewritten implementation of PostgreSQL 18.3 maintained by malisper that maintains binary compatibility with the upstream server while exploring architectural improvements. Understanding the performance differences between pgrust and PostgreSQL requires examining three core redesigns: the concurrency model, language choice, and memory management strategies.

Concurrency Model: Processes vs Threads

PostgreSQL's Process-Per-Connection Architecture

Traditional PostgreSQL uses a process-per-connection model where each client connection spawns a separate OS process via fork(). This design incurs heavy context-switch overhead and duplicated memory pages through copy-on-write semantics. When handling thousands of concurrent connections, the scheduler overhead and memory duplication create significant bottlenecks in transaction-heavy workloads.

pgrust's Thread-Per-Connection Design

pgrust replaces processes with threads, running one OS thread per client within a shared address space. This eliminates the costly fork() operations and allows CPU caches to reuse data across connections more effectively. According to the repository's performance benchmarks at line 37 of the README, this architectural shift alone yields approximately 50% faster performance on typical transaction workloads.

Language Choice and Compilation Advantages

C Implementation Limitations

PostgreSQL's C implementation relies on manual memory management and pointer arithmetic, which limits the compiler's ability to perform aggressive inlining and optimizations. Safety-related bugs in memory management can also cause hidden stalls that degrade performance unpredictably.

Rust's Zero-Cost Abstractions

pgrust is implemented in Rust, which provides zero-cost abstractions and guaranteed memory safety without runtime garbage collection. The Rust compiler produces tighter machine code through aggressive inlining while eliminating costly runtime checks. These optimizations contribute to 300× speedups on analytical queries where tight data-processing loops dominate execution time.

Memory Management and Execution Pipeline

Process-Local State in PostgreSQL

PostgreSQL relies heavily on process-local static globals and per-process memory pools (such as Backend and ExecutorState structures). Updating these structures requires copying data across processes during parallel operations, creating latency and contention in both read-only and write-heavy workloads.

Thread-Local Storage in pgrust

pgrust replaces process-local storage with thread-local storage using thread_local! macros throughout the engine. This design eliminates inter-process copying and enables true sharing of reusable caches. You can see this implementation in crates/common/wait_error/src/lib.rs, which handles error states without cross-process synchronization, and in crates/backend/rmgrdesc_next/src/*, where core resource-manager descriptors for WAL and transaction logs benefit from shared-memory access patterns.

The PL/pgSQL parser in crates/pl/plpgsql/src/plpgsql_gram/src/parser.rs demonstrates how the original C parser was ported while preserving thread-local parsing state, reducing contention during complex query compilation.

Benchmark Results and Real-World Impact

The performance differences between pgrust and PostgreSQL vary significantly by workload type:

  • Transaction workloads (OLTP): Approximately 50% faster than PostgreSQL due to reduced context-switching and thread creation overhead
  • Analytical workloads (OLAP): Approximately 300× faster than PostgreSQL, while remaining only 2× slower than ClickHouse on ClickBench benchmarks

Because pgrust maintains the same on-disk format as PostgreSQL, these performance gains require no migration work—existing data directories work immediately with the pgrust binary.

Implementation Examples

The following examples demonstrate pgrust's drop-in compatibility while illustrating its performance-oriented architecture:

// Launching the pgrust server (equivalent to postgres -D <dir>)
use std::process::Command;

fn launch_pgrust(data_dir: &str) {
    let status = Command::new("target/release/postgres")
        .args(&[
            "-D", data_dir,
            "-F",                 // disable fsync for demo
            "-c", "listen_addresses=", // bind to all interfaces
            "-p", "5432",
        ])
        .status()
        .expect("failed to launch pgrust");
    assert!(status.success());
}
// Connecting with the built-in libpq client (identical to psql)
use libpq::Connection;

fn run_simple_query() -> Result<(), libpq::Error> {
    let mut conn = Connection::new("host=/tmp dbname=postgres user=postgres")?;
    let rows = conn.query("SELECT version(), 1 + 1 AS two", &[])?;
    for row in rows {
        let version: &str = row.get(0);
        let two: i32 = row.get(1);
        println!("{} → {}", version, two);
    }
    Ok(())
}

Both snippets use identical command-line arguments and SQL as traditional PostgreSQL deployments, as implemented in crates/interfaces/libpq/fe/src/lib.rs, ensuring compatibility while gaining the architectural benefits described above.

Summary

  • Thread-per-connection architecture replaces PostgreSQL's process-per-connection model, reducing context-switch overhead by approximately 50% on transaction workloads
  • Rust's zero-cost abstractions enable aggressive compiler optimizations that deliver 300× performance improvements on analytical queries compared to the C implementation
  • Thread-local storage in files like crates/common/wait_error/src/lib.rs and crates/backend/rmgrdesc_next/src/* eliminates inter-process copying and enables efficient cache sharing
  • Binary compatibility with PostgreSQL 18.3 allows immediate deployment using existing data directories without migration overhead
  • Performance profile ranges from 50% faster on OLTP to 300× faster on OLAP workloads, with only 2× overhead compared to specialized analytical databases like ClickHouse

Frequently Asked Questions

Is pgrust binary-compatible with PostgreSQL?

Yes, pgrust is designed to be binary-compatible with PostgreSQL 18.3. It uses the same on-disk format and network protocol, allowing you to start pgrust with an existing PostgreSQL data directory using standard command-line arguments like postgres -D <directory>. The crates/interfaces/libpq/fe/src/lib.rs implementation maintains wire-protocol compatibility with existing PostgreSQL clients.

How does pgrust handle WAL and transaction logs?

pgrust implements WAL (Write-Ahead Logging) and resource-manager descriptors in crates/backend/rmgrdesc_next/src/*, utilizing thread-local storage to manage transaction state. This differs from PostgreSQL's process-local static globals, allowing concurrent access to transaction logs without the overhead of inter-process communication or memory copying.

Can I migrate existing PostgreSQL data to pgrust?

No migration is necessary. Because pgrust maintains the same on-disk binary format as PostgreSQL 18.3, you can point pgrust to an existing PostgreSQL data directory and start the server immediately. This zero-migration path allows you to gain performance benefits—ranging from 50% to 300× depending on workload—without exporting and importing data.

What workloads benefit most from pgrust's architecture?

Analytical (OLAP) workloads benefit most dramatically, with up to 300× performance improvements due to Rust's efficient handling of tight data-processing loops. Transaction-heavy (OLTP) workloads see approximately 50% improvements from the thread-per-connection model. Workloads with high connection counts and frequent context switching see the most significant gains compared to traditional PostgreSQL process-based architecture.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →