NativeLink
Contribute

Develop with Nix

The dev shell that generates the bazelrc files the rest of the build assumes, and what is actually inside it.

Who this is for: anyone who wants the toolchain CI uses, and anyone working on LRE, which needs it. What you'll have at the end: the shell, the five generated bazelrc files it produces, and an accurate list of what it does and does not contain. Time: twenty minutes, mostly download.

The flake in the repository root is where almost all of NativeLink's tooling lives. Entering the shell is not just a convenience: the shell hook is what writes the bazelrc fragments that .bazelrc pulls in with try-import, and try-import means their absence is silent. A build outside the shell is not a broken build; it is a differently configured one.

Install Nix

The next-gen Nix installer is the easiest path:

curl -sSfL https://artifacts.nixos.org/nix-installer | sh -s -- install --enable-flakes

The --enable-flakes flag turns on the nix-command and flakes experimental features, which the repository's flake needs.

Enter the dev shell

git clone git@github.com:yourusername/nativelink
cd nativelink
nix develop

First run downloads the toolchain, which takes a few minutes. After that, entering is close to instant; everything is content-addressed in /nix/store.

Install `direnv` and stop thinking about this

CONTRIBUTING.md recommends it strongly, and the reason is that the shell has to be re-entered after every branch switch or change to a .nix file. direnv does that for you:

nix profile install nixpkgs#direnv
# add the hook for your shell: https://direnv.net/docs/hook.html
# then, in the repo: direnv allow

To check the environment is active: env | grep NIX should print several *NIX_* variables.

What entering the shell generates

This is the part that matters and the part that is invisible. The shell hook writes five things into your working tree:

Generated fileWhat it does
.pre-commit-config.yamlSymlink enabling the repo's pre-commit hooks
lre.bazelrcPoints Bazel at the LRE toolchains
nativelink.bazelrcGives your builds access to NativeLink's read-only cache
nixos.bazelrcAdds the required NixOS binary paths (NixOS only)
darwin.bazelrcConfigures Darwin libs and frameworks (macOS only)

.bazelrc picks all four bazelrc fragments up with try-import, so outside the shell Bazel silently proceeds without them. That is why a build can succeed outside Nix and still not match CI.

What is in the shell

The package list is in devShells.default. Broadly:

Rust and build: a bazel wrapper around Bazelisk (it unsets TMPDIR first), the pinned stable Rust toolchain from the LRE overlay, rust-analyzer, buck2, python3, git, pre-commit, git-cliff.

Web: bun, nodejs_22, lychee, the Playwright driver. This is what lets you work on the docs without installing anything.

Infrastructure: kubectl, kubernetes-helm, kustomize, kubectx, kind, cilium-cli, fluxcd, pulumi, skopeo, dive, cosign, trivy, awscli2, google-cloud-sdk, docker-client, tektoncd-cli, go.

Docs and prose: vale, which is the style linter the docs are checked against.

Repo-specific helpers: the toolchain generators, the local image builders, local-image-test, and the LRE clang.

Running things inside the shell

Everything from the Bazel and Cargo workflows works unchanged. The shell guarantees the versions, and supplies the bazelrc fragments those workflows assume.

The two commands worth knowing that only exist here:

pre-commit run -a                       # the full pre-commit suite
nix build .#nativelinkCoverageForHost   # HTML coverage report in ./result

LRE and worker images

The flake builds the LRE worker images rather than exposing an LRE shell. The ones you are likely to want:

nix build .#nativelink-worker-lre-cc
nix build .#nativelink-worker-lre-rs
nix build .#nativelink-worker-lre-java

lre.bazelrc, generated on entering the shell, is what points a local Bazel build at the matching toolchains. See LRE for what the scheme is doing and why the /nix/store paths have to match on both sides.

When Nix isn't worth it

For a typo fix, a doc tweak or a single unit test, the Cargo workflow is faster to get into and nothing will go wrong. Reach for Nix when you are touching the build graph, working on LRE, chasing a difference between your machine and CI, or working on the docs, since vale and bun both come from here.

Common questions

NextRepository and crate map

With a working shell, the next question is where your change goes. Twelve crates, a strict layering, and six places the first guess is wrong.

On this page