NativeLink

Examples and templates

Runnable configs, deployment topologies, and project scaffolds you can copy, plus the three client-side patterns most teams actually adopt.

Who this is for: anyone who wants a working starting point rather than a blank file. What you'll have at the end: the right example for your situation, and a client-side pattern that matches how you want work split between laptops and a fleet. Time: varies; the point of this page is to find the thing, not to read it.

Before you start

A cache serving hits to your build. If you don't have one yet, start with Getting started.

Three kinds of starting point ship in the repo, and they answer different questions.

You wantLook in
A NativeLink config for a specific backend or shapenativelink-config/examples/
A whole deployment topology to rundeployment-examples/
A client project pre-wired to a hermetic toolchainnix flake init

Server configs

nativelink-config/examples/

is the largest and most useful collection. Every file is a complete, loadable config.

FileWhat it demonstrates
basic_cas.json5The minimum cache, the quickstart's config
filesystem_cas.json5On-disk CAS with compression, dedup, and size partitioning in front of it
local_rbe_self_test.json5A complete cluster in one process: CAS, AC, scheduler, worker
stores-config.json5One block per store type, generated from the stores.rs doc comments for testing
chunking_cas.json5Content-defined chunking
advanced_http.json5HTTP/2 listener tuning (keepalive, stream limits, window sizes)
s3_backend_with_local_fast_cas.json5fast_slow over S3, the canonical production store
gcs_backend.json5, azure_blob_backend.json5, r2_backend.json5, oci_backend.json5, ontap_backend.json5The other object-storage backends
redis.json5, mongo.json5Redis and MongoDB stores
worker_with_redis_scheduler.json5A scheduler whose state lives in Redis
scheduler_match_logging_disable.json5Turning off the periodic match dump
tmpfs-worker.json5A worker whose fast tier and work directory sit on a tmpfs mount
legacy_service_config.json5The older service config shape, for migrations
README.md

Start from the file closest to your situation and read its comments; several of them explain constraints you'd otherwise discover the hard way, like why a worker's fast store must be a filesystem store.

How-to guides is the task-oriented version of that table if you already know which backend you want.

Deployment topologies

deployment-examples/

holds deployment material rather than single config files: the docker-compose/ stack, a RHEL 8 Dockerfile (rhel/), the metrics pipeline configs and dashboards (metrics/), and the persistent-worker rule sketches (persistent-workers/).

The docker-compose/ one is the most useful of them, because it is the topology the project's own integration tests run against: a CAS process on 50051, a scheduler with the execution and AC services on 50052, a worker, and the scheduler's worker API on 50061 left unpublished so it is only reachable inside the compose network.

cd deployment-examples/docker-compose
docker compose up

Local testing covers running this and pointing a build at it; Production configuration covers what changes when it stops being a demo.

Project templates

The flake ships templates for the client side: a project already wired to a Nix-pinned toolchain.

nix flake show github:TraceMachina/nativelink

That command is the source of truth

Templates get added and removed between releases. Run it rather than trusting a hardcoded list, including the one below, which reflects what ships as of this page's last update.

TemplateWhat it gives you
bazelA Bazel cc_binary project pre-wired for Local Remote Execution: Nix-pinned toolchain, the LRE Bazel module, and a user.bazelrc you point at a cache and executor
mkdir my-rbe-test && cd my-rbe-test
nix flake init -t github:TraceMachina/nativelink#bazel
git init && git add -A   # what templates/README.md tells you to do; a flake in a git repo only sees tracked files
nix develop

The template does not bundle a NativeLink server; you point it at one you already have. It is also Linux-only, because the lre-cc toolchain it wires in currently supports x86_64-linux only. Toolchains and hermeticity walks the whole flow with real output, including the user.bazelrc values.

To customise: it's a flake, so fork and edit. The usual changes are pointing user.bazelrc at a real cluster, adding platform properties in platforms/BUILD.bazel, and pinning inputs.nativelink.url in flake.nix to a specific commit, kept in sync with the local-remote-execution override in MODULE.bazel.

Three client-side patterns

Independently of which config you start from, there are three ways teams wire their builds. Most adopt them in this order.

Pattern A: Cache only

Every action runs locally; results land in the shared cache. No worker fleet needed, which makes it the cheapest thing that helps.

bazel build //... \
  --remote_cache=grpc://nativelink.internal:50051 \
  --remote_instance_name=main

Right when you have one CI environment building similar things repeatedly, when you want shared caching across laptops without operating workers, or when you're still evaluating. This is Getting started.

Pattern B: Cache plus execution

Actions ship to a worker fleet; the cache underneath stores everything.

bazel build //... \
  --remote_cache=grpc://nativelink.internal:50051 \
  --remote_executor=grpc://nativelink.internal:50052 \
  --remote_instance_name=main \
  --jobs=200

--jobs=200 is the change people forget. Without it Bazel dispatches only as many actions as your laptop has cores, and the fleet sits idle; the limiting factor is supposed to be pool size, not local CPU count.

Right when full builds take hours, when you're trying to shrink a CI fleet, or when you need actions to run on hardware developers don't have.

Pattern C: Hybrid

Small actions local, everything else remote, decided by policy.

bazel build //... \
  --remote_cache=grpc://nativelink.internal:50051 \
  --remote_executor=grpc://nativelink.internal:50052 \
  --remote_instance_name=main \
  --modify_execution_info=Javac=+no-remote-exec \
  --strategy=Javac=local

This forces Javac local (for very small compilations the round-trip dominates) while everything else goes remote.

Right when your workload mixes very fast and very slow actions, or when latency to the fleet is high enough that small actions lose. Reach for it when you have telemetry showing where time actually goes, not before; Tuning covers getting that telemetry.

Choosing

PatternSetup costWhere the win comes fromWhat it costs
Cache onlyLowRepeated work becomes freeStorage
Cache + executionMediumCache misses fan out across a fleetWorker compute
HybridHighAvoids paying round-trips on trivial actionsWorker compute + tuning effort

The speedup numbers you'll see quoted for these vary by an order of magnitude between workloads, and mostly reflect how much of a given build is cache-missing compilation. Measure your own before committing to a shape.

FAQ

NextConfiguration

Stop copying examples and write the config yourself.

SidewaysProduction configuration

The full-size version of the compose topology, with the reasoning.

On this page