Open-Source Wikis

/

Neon

/

Extensions and Postgres fork

/

The vendored Postgres fork

neondatabase/neon

The vendored Postgres fork

vendor/postgres-v{14,15,16,17} are git submodules pointing at neondatabase/postgres branches that hold lightly patched copies of upstream PostgreSQL. They are the source from which Neon's compute nodes (and the WAL-redo subprocess used by the pageserver) are built.

The exhaustive technical writeup of every patch is docs/core_changes.md. This page summarizes what kinds of patches exist, why they exist, and how they're maintained.

Why patches at all?

Most Neon-specific behavior lives in the pgxn/neon extension. But Postgres's extension API does not yet expose every hook Neon needs. The patches add the hook points; the extension uses them. The long-term plan stated in docs/core_changes.md:

The long-term goal is to eliminate all these changes, by submitting patches to upstream and refactoring code into extensions, so that you can run unmodified PostgreSQL against Neon storage.

In practice, some patches have been retired as upstream landed equivalent functionality (the v17 streaming-read work, for example). Others remain.

Categories of changes

docs/core_changes.md groups them into:

Changes needed in the compute node

  • Prefetching. Neon's latency to the pageserver is much higher than to local disk, so aggressive prefetching is critical. Patches add prefetching paths for seq scans, index scans, and bitmap scans. v17's streaming-read work is expected to absorb some of this.
  • t_cid in heap WAL records. Upstream's heap WAL records don't include the inserter's command id; replicas don't need it because they never reread their own row mid-transaction. Neon does, because the pageserver reconstructs page versions on demand and a still-running transaction may reread its own newly-inserted rows. The patch widens heap WAL records by 4 bytes.
  • Custom WAL records via pgxn/neon_rmgr. Hooks for registering new WAL resource managers (used for things like Neon-specific catalog-state changes).
  • Walproposer hooks. Hooks at WAL insertion to feed the walproposer in pgxn/neon.
  • smgr hooks. Hook points for smgropen, smgrread, smgrwrite, smgrnblocks, etc. so the pgxn/neon extension can install a pageserver-backed implementation.
  • Backpressure hooks. A hook in XactLockTableWait and friends so the compute can stall when the pageserver/safekeepers are too far behind.
  • Initdb and bootstrap. Smaller adjustments so a freshly-bootstrapped Postgres can boot from a basebackup that itself came from the pageserver rather than from pg_basebackup.

Changes needed in the WAL-redo subprocess

  • --wal-redo mode flag. A startup mode that runs Postgres just enough to apply WAL records to a base page image.
  • Read records over a pipe. Replace WAL reading from disk with reading from a pipe.
  • Sandbox setup. Hooks so the harness in pgxn/neon_walredo/ can install seccomp filters and limit syscalls.

For each patch class, docs/core_changes.md documents the affected files in upstream, why the patch is needed, and the planned path to retire it.

How the multi-version build works

Makefile declares POSTGRES_VERSIONS = v17 v16 v15 v14 and then loops over them. postgres.mk (included from the top-level Makefile) defines the per-version build rules:

postgres-install-v17:        # configure + make + install vendor/postgres-v17 into pg_install/v17/
postgres-headers-install:    # alias for the headers needed before building Rust postgres_ffi
neon-pg-ext-v17:             # build pgxn/* against pg_install/v17
walproposer-lib:             # build a static walproposer.a against v17

The Rust libs/postgres_ffi/ crate has per-version submodules so it can interoperate with all four ABIs at runtime. The pageserver, when running the WAL-redo subprocess for a tenant, picks the Postgres binary matching the tenant's pg_version.

Updating Postgres

docs/updating-postgres.md (in the repo) describes the workflow:

  1. Open a PR on the neondatabase/postgres fork that bumps the upstream merge target.
  2. Resolve any conflicts by re-applying Neon patches. Most patches are stable; a few areas (smgr hooks, WAL record format) are higher friction.
  3. Run the matrix in CI.
  4. Once green, update the submodule pointer in vendor/postgres-vXX here.
  5. Cross-check pgxn/neon/neon_pgversioncompat.h for any new shims needed.

Adding a brand-new major version (e.g. v17) goes through the same flow plus a new vendor/postgres-v17/ submodule and a new entry in POSTGRES_VERSIONS.

Where to read

  • docs/core_changes.md — exhaustive patch-by-patch description.
  • docs/updating-postgres.md — upgrade workflow.
  • pgxn/neon/neon_pgversioncompat.h — compile-time shims for the 4 supported versions.
  • The submodule itself (cd vendor/postgres-v17 && git log) for the actual patches.

Why this matters for contributors

Most Neon contributors never touch the vendored Postgres. The exception is the compute team. If you find yourself in vendor/postgres-v*, expect:

  • A separate PR on neondatabase/postgres paired with your PR here.
  • pg_install/ rebuild times in the multi-minute range.
  • Tests across all four supported PG versions (CI handles this automatically).
  • A reviewer who is paying close attention to whether the change can instead be done as an extension hook addition, since that's the long-term plan.

See also

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

The vendored Postgres fork – Neon wiki | Factory