Open-Source Wikis

/

Neon

/

How to contribute

/

Development workflow

neondatabase/neon

Development workflow

A practical day-in-the-life for someone editing Neon.

Setting up your tree

After cloning (with --recursive for the Postgres submodules) and running make once, the typical inner loop becomes:

# Rebuild only what changed
make -j$(nproc) -s

# Or skip Postgres if its sources haven't moved
PG_INSTALL_CACHED=1 make -j$(nproc) -s

PG_INSTALL_CACHED=1 is the trick to avoid the multi-minute Postgres rebuild when you've only touched Rust. The Makefile honors this and short-circuits the Postgres install steps (postgres-headers-install, postgres-install-*).

The cargo neon alias

.cargo/config.toml aliases cargo neon to running the neon_local binary from control_plane/. This is how every contributor starts and stops the storage stack:

cargo neon init        # bootstrap a .neon/ working dir
cargo neon start       # broker + pageserver + safekeeper
cargo neon tenant create --set-default
cargo neon endpoint create main
cargo neon endpoint start main
cargo neon endpoint stop main
cargo neon stop

If something gets wedged, rm -rf .neon and start over is safe — the directory holds nothing you can't regenerate.

Editing one component at a time

Most days you only touch one Cargo crate. Build / test loop:

# Build only the pageserver, with testing feature on
cargo build -p pageserver --features=testing

# Run only the unit tests in one crate
cargo nextest run -p pageserver

# Run a specific test
cargo nextest run -p pageserver -E 'test(some_test_name)'

When you change shared API crates (libs/pageserver_api, libs/safekeeper_api, libs/compute_api), rebuild the consumers explicitly — cargo build -p pageserver -p storage_controller -p compute_tools.

Working with the Postgres submodule

The vendor/postgres-v* trees are submodules. They are checked out automatically by make, but you may need to update them manually after pulling main:

git submodule update --init --recursive

If you change C code under pgxn/neon/, the neon-pg-ext-v{14,15,16,17} Makefile targets rebuild the per-version .so. The compute uses these .so files — if you start a compute and don't see your new behavior, double-check that you re-ran make.

If you change C code in vendor/postgres-v* itself, you generally also need to land a PR on the neondatabase/postgres fork; that fork is where the submodule points.

Branching and rebasing

git checkout main
git pull
git checkout -b storage/some-feature
# ... work ...
git rebase main
git push -u origin storage/some-feature

For long-running branches that fall behind:

git fetch origin
git rebase origin/main
# resolve conflicts, rebuild, retest
git push --force-with-lease

Force-pushing tiny fixups onto an open PR is discouraged once review has started — CONTRIBUTING.md calls this out explicitly because reviewers have to re-read everything.

Pre-commit hook

Install once:

make setup-pre-commit-hook
# or
ln -s ../../pre-commit.py .git/hooks/pre-commit

The hook (in pre-commit.py) runs rustfmt on staged Rust files and the Python style checks listed in docs/sourcetree.md. Skip with git commit --no-verify only when you have a clear reason.

Reformatting and linting before pushing

./scripts/reformat        # rustfmt + ruff format + minor cleanups
./run_clippy.sh           # cargo clippy across the workspace with the project's lint flags
poetry run ruff check .   # python lints, repo root
poetry run mypy .         # python types, repo root only

The clippy invocation reads .neon_clippy_args for the workspace-wide lint flags.

Updating dependencies

Adding a new Rust crate to a workspace member also requires updating workspace_hack/:

cargo hakari generate
cargo hakari manage-deps

If you don't have cargo-hakari installed, cargo install cargo-hakari first.

For Python deps, edit pyproject.toml (or use poetry add) and commit the updated poetry.lock.

CI

Pushing to a PR triggers .github/workflows/build_and_test.yml (the main workflow, ~73 KB of YAML) which runs:

  • cargo deny check (cargo-deny.yml)
  • Rust + Python codestyle checks (_check-codestyle-rust.yml, _check-codestyle-python.yml)
  • Build and test on Linux and macOS (build-macos.yml, _build-and-test-locally.yml)
  • Sanitizer builds (build_and_test_with_sanitizers.yml)
  • Periodic benchmarks on cron triggers (benchmarking.yml, proxy-benchmark.yml)

Many of the workflow files are _-prefixed and meant to be reused; the public entry points are the unprefixed ones.

A few smaller tools

  • ./scripts/pysync — installs the Python integration-test dependencies via Poetry.
  • ./scripts/pytest — wrapper that sets the right env vars and runs pytest against test_runner/.
  • cargo neon storage_broker, cargo neon pageserver, etc. — sub-commands of neon_local that operate on a specific service.
  • pageserver/ctl (pagectl binary) — offline diagnostic tool that can dump layer files, page contents, etc. Useful when triaging "why does this tenant think LSN X is missing?"

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

Development workflow – Neon wiki | Factory