How the Seams Architecture Facilitates Porting PostgreSQL to Rust

The seams architecture in pgrust isolates PostgreSQL's C implementation through small, ABI-compatible Rust functions that enable gradual, test-driven migration without breaking binary compatibility.

The malisper/pgrust project implements a seam-based architecture to systematically port PostgreSQL from C to Rust. This approach allows developers to replace individual C functions with Rust implementations while keeping the server runnable and fully compatible with existing data directories. By defining stable contracts between legacy C code and new Rust logic, the architecture supports a step-by-step migration that preserves decades of battle-tested PostgreSQL behavior.

What Is the Seams Architecture?

A seam is a small, well-defined Rust function that mirrors the signature and semantics of an existing C routine. Each seam is declared using the seam_core::seam! macro, which generates the necessary bindings to bridge the two languages.

For example, the signal handling seam in crates/port/port_pqsignal_seams/src/lib.rs declares a Rust implementation compatible with PostgreSQL's pqsignal function:

// crates/port/port_pqsignal_seams/src/lib.rs
seam_core::seam!(
    /// `void pqsignal(int signo, pqsigfunc func)` (`src/port/pqsignal.c`,
    /// symbol `pqsignal_be`) — install a signal handler via `sigaction` with
    /// `SA_RESTART` (plus `SA_NOCLDSTOP` for `SIGCHLD`). The backend variant
    /// returns `void` (unlike the legacy libpq `pqsignal`, which reports the
    /// previous disposition); a failing `sigaction(2)` is a coding error
    /// (`Assert(false)` in C), not an ereport, so the seam is infallible.
    pub fn pqsignal(signo: i32, func: signal::SigHandler)
);

When the C code is compiled, the build system generates a stub that forwards calls to the matching Rust seam. The Rust side implements the same signature and semantics, acting as a drop-in replacement that can be swapped without modifying surrounding C code.

Gradual Migration Without Service Disruption

The seams architecture enables incremental porting by isolating each PostgreSQL C file into a corresponding seam module. Examples include pg_crc32c_seams for checksum algorithms, pg_numa_seams for NUMA-aware memory allocation, and walsender_seams for replication logic.

This modular approach delivers specific advantages:

  • Per-function replacement: Developers can rewrite one routine at a time, compile the Rust crate, and link it into the existing PostgreSQL binary without touching unrelated subsystems.
  • Continuous operation: The server remains runnable throughout the migration, allowing real-world testing at every stage.
  • Rollback capability: If a Rust implementation introduces a regression, the build system can revert to the original C version by updating the seam stub.

Maintaining Binary Compatibility

Seams expose the exact C ABI—including types and calling conventions—to ensure the Rust-produced binary remains compatible with existing PostgreSQL data directories. The linker resolves generated C wrapper symbols to the Rust implementations, producing a binary that boots against a standard PostgreSQL data directory without format changes or startup script modifications.

The build process follows three stages:

  1. Generate C stubs – For each seam module, the system emits a small C wrapper that forwards calls to the Rust function via the seam_core runtime.
  2. Link – The Rust crate links into the final PostgreSQL executable.
  3. Initialize – At server startup, init_seams() registers all Rust implementations, overwriting default C behavior at runtime.

Test-Driven Porting with Existing Suites

The architecture preserves PostgreSQL's existing regression test infrastructure. Because each seam maintains identical semantics to its C predecessor, the original PostgreSQL regression suite—comprising over 46,000 queries—runs unchanged against the seam-backed build. This guarantees functional parity while refactoring, catching subtle behavioral differences immediately rather than after months of development.

Isolating Unsafe Code Boundaries

Memory safety improves dramatically through seam isolation. Only the seam stub itself uses unsafe blocks to bridge C and Rust, while the underlying implementation remains safe Rust. This pattern reduces the surface area for memory corruption bugs and makes security audits more manageable by concentrating unsafe code into thin, well-reviewed adapter layers.

Runtime Implementation Swapping

Seams support runtime replaceability, allowing the system to switch between C and Rust implementations without recompilation. The init_seams() function determines at startup whether to use the original C function or a pure-Rust algorithm. This enables performance experiments—such as swapping the C pg_crc32c implementation for a Rust SIMD version—without rebuilding the entire server.

Key Seam Components in pgrust

The pgrust repository organizes seams into specific crates that mirror PostgreSQL's internal structure:

Summary

  • The seams architecture defines stable contracts between C and Rust through ABI-compatible function declarations using seam_core::seam!.
  • Gradual migration proceeds one function at a time via modules like pg_crc32c_seams and pg_numa_seams without breaking server operation.
  • Binary compatibility with existing PostgreSQL data directories is preserved through exact C ABI matching and linker-level integration.
  • Over 46,000 existing regression tests validate functional parity throughout the porting process.
  • Unsafe code is isolated to thin seam stubs, keeping the majority of the implementation in safe Rust.
  • Runtime swapping via init_seams() enables performance testing of Rust implementations against C originals without recompilation.

Frequently Asked Questions

How does the seams architecture maintain PostgreSQL's binary compatibility during the Rust port?

The architecture exposes the exact C ABI—including types, calling conventions, and symbol names—through generated C stubs that forward calls to Rust implementations. According to the malisper/pgrust source code, these stubs allow the resulting binary to link against existing PostgreSQL data directories and startup scripts without modification, ensuring the Rust build boots a real PostgreSQL data directory.

Can individual C functions be replaced without rebuilding the entire PostgreSQL server?

Yes. Each seam module isolates a specific C function or small group of functions. Developers implement the Rust version in crates like crates/port/port_pqsignal_seams, run cargo build, and link only that crate into the existing binary. The init_seams() function registers the new implementation at startup, enabling piecemeal migration without full recompilation.

How does the architecture handle memory safety when bridging C and Rust code?

Only the seam stub uses unsafe blocks to interface with C, while the underlying Rust implementation remains safe code. This concentrates memory-unsafe operations into thin, auditable adapter layers, significantly reducing the attack surface compared to the original C codebase.

What role do PostgreSQL's existing regression tests play in the porting process?

The original PostgreSQL regression suite runs unchanged against the seam-enabled build, executing over 46,000 queries to verify functional parity. Because seams mirror C function signatures exactly, these tests validate that Rust implementations behave identically to their C predecessors, catching regressions immediately during the port.

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 →