NativeLink

Configuration

The config model on one page, so you can read and write a NativeLink config instead of copying one.

Who this is for: anyone running a cluster they got working by copying an example, who now needs to change it. What you'll have at the end of this section: the ability to read any NativeLink config and write one from an empty file. Time: an afternoon, most of it on the capstone.

Before you start

A cluster you got running by copying an example, for instance from Examples and templates.

One file, six keys

A NativeLink deployment of any shape (one process on a laptop, a sharded fleet across three regions) is described by a single JSON5 file. It has exactly six top-level keys, and only two of them are required.

KeyRequiredShapeWhat it holds
storesyesarrayEvery storage backend this process can use, each with a name
serversyesarrayListeners, and which services are exposed on each
schedulersnoarrayQueues that match actions to workers
workersnoarrayExecutors that run actions, in this process
globalnoobjectProcess-wide settings: file limits, default digest function
experimental_origin_eventsnoobjectEvent publishing, still experimental
CasConfig

schedulers and workers are optional because a cache-only deployment has neither. That's Getting started: a config with just stores and servers is a complete, valid NativeLink cache.

How a request traverses them

Read that diagram as: the servers array is the only entry point, and everything else is reached from it by name. A service doesn't contain a store, it names one. A worker doesn't contain a scheduler, it dials one over the worker API. The names are the wiring.

This is why the config can describe both a single process and a fleet without changing shape. Split the same file into three (one with stores and a CAS server, one with schedulers and an execution server, one with workers) and the names become network addresses instead of in-process references. Nothing else changes.

Everything is a named array

Every top-level collection is an array of objects, not a map keyed by name. Stores and schedulers carry their name beside the type key; workers carry it inside the local block; servers have an optional name:

schedulers: [
  {
    name: "MAIN_SCHEDULER",
    simple: {
      supported_platform_properties: { cpu_count: "minimum" },
    },
  },
],

The name sits beside the type key rather than wrapping it, because the type-specific fields are flattened into the same object.

A typo is a startup error, not a silent default

Nearly every struct in the config crate is #[serde(deny_unknown_fields)]. Misspell a key and the process refuses to start and tells you which key it didn't recognise, rather than ignoring it and behaving strangely three hours later.

This is worth knowing because it changes how you should edit configs: the fastest way to check a change is to start the binary. It parses the whole file before it binds a single socket.

The pages, in order

Learn the mechanics

  • The config file: JSON5, environment substitution, how the binary finds the file, and how to check one before you trust it.

Learn the four sections

  • Stores: declaring and naming stores, and the one idea that unlocks the rest of the system: stores compose.
  • Servers and services: listeners, the eleven services, and the port split that keeps workers off the public interface.
  • Schedulers and workers: the minimum of each, and the properties contract between them.

Put it together

Start here, or skip ahead

Start here if you have a cluster running from a copied example and want to understand what you copied.

Go back a section if nothing is running yet. Getting started gets you a cache, and Remote execution gets you workers; both hand you a working config you can then read here.

Skip ahead to How-to guides if you know exactly which backend or feature you want and just need the block that does it.

Skip ahead to Production configuration if what you actually want is the shape a real fleet runs, rather than the model behind it.

NextThe config file

JSON5, ${VAR:-default} substitution, and how to find out a config is wrong before it takes a cluster down with it.

SidewaysConfiguration reference

Generated from the Rust source: every field, every default, every constraint. This section is for understanding; that one is for lookups.

On this page