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) -sPG_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 stopIf 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 --recursiveIf 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-featureFor long-running branches that fall behind:
git fetch origin
git rebase origin/main
# resolve conflicts, rebuild, retest
git push --force-with-leaseForce-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-commitThe 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 onlyThe 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-depsIf 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 runspytestagainsttest_runner/.cargo neon storage_broker,cargo neon pageserver, etc. — sub-commands ofneon_localthat operate on a specific service.pageserver/ctl(pagectlbinary) — 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.