Remote Execution is now generally available.
nsc bazel setup includes both the remote executor and
the remote cache, so remotely executed actions share artifacts with your CI and
local builds.
Getting started
Remote Execution is enabled for every workspace. Usensc bazel setup to create a Bazel
configuration file for the execution cluster:
Configure execution access
How it works
A Bazel Remote Execution cluster has three components:- Scheduler: accepts Bazel Remote Execution API requests and assigns actions to workers.
- Storage: stores content-addressable storage (CAS) entries durably across the cluster.
- Workers: execute Bazel actions.
Example: Linux host to Linux workers
This example runs Bazel from a Linux host and executes actions on Linux workers. It uses a public Bazel repository so you can try the flow without changing your own project first.Example: Linux host to macOS workers
Bazel can also route selected actions to macOS workers from a Linux client. The linux-to-mac-rbe-demo repository demonstrates that setup. This example requiresmacos/arm64 workers to be enabled for your workspace. If
you see an error such as no on-demand worker capacity configured for platform "macos/arm64", reach out to the Namespace team to enable macOS worker capacity.
Remote Execution from a Devbox
You can enable Bazel Remote Execution on any Devbox, including one that already exists. Run setup from inside the Devbox, whether or not it was created with Bazel caching enabled.Create a Devbox
Point Skip this step if you already have a Devbox with your Bazel project checked out.
--checkout at the repository that holds your Bazel workspace, so the
Devbox starts with the project already cloned:Enable remote execution
--remote=true is on by default, so this writes both
the remote executor and the remote cache into the configuration. Pass
--remote=false for a cache-only setup.Devboxes store the path to the If that comes back empty, set it yourself with:
bazelrc in the BAZELRC environment variable, which lets scripts and later examples name the configuration without hardcoding the path. Check that it is set:bazelrc checked into your
repository rather than editing the generated one, since setup overwrites it each
time it runs. Combine the two with repeated --bazelrc flags, using the
BAZELRC environment variable that the Devbox sets to the generated file:
Remote Execution from CI
Authenticating Remote Execution with a revocable token requires nsc v0.0.544 or later. Run
nsc version ensure --at_least 0.0.544 to check and update the CLI if needed.nsc bazel setup uses your interactive login and writes a
bazelrc that authenticates to the cluster with a short-lived mTLS client
certificate. For CI/CD pipelines, automation, or any environment without an
interactive login, you can instead authenticate with a
revocable token.
Revocable tokens are long-lived but can be revoked at any time from
cloud.namespace.so/user/sessions or
with nsc token revoke.
Create a revocable token
Use Set
nsc bazel create-token to create
a token with the permissions required for Remote Execution and write it to a
file:--expires_in to a duration of up to 365 days.Generate a bazelrc with the token
Pass the token file to the setup command. This provisions a cluster that uses
the revocable token to obtain short-lived credentials:
Additional configuration options
Bazel execution properties can reserve worker CPU capacity and select the isolation mode on Linux workers:--remote_default_exec_properties to apply a property to actions that do
not override it:
Reserve CPU capacity
Thecpu property tells the scheduler how much CPU capacity to
reserve while an action runs. Values can be whole or fractional numbers, such
as "2" or "0.5". The scheduler considers both execution slots and CPU
reservations when assigning concurrent actions to a worker.
The reservation is a scheduling input, not a CPU limit applied to the action.
An omitted or zero value does not reserve CPU capacity beyond the action’s
execution slot.
resources:cpu is accepted as an alternative property name.
Select action isolation
Thenamespace_action_isolation property controls how a Linux worker runs an
action:
The workspace default is
none unless configured otherwise.
Sandboxed isolation is supported only on Linux workers at the moment.
Contact support@namespace.so to change the setting.
Sandboxed actions receive an isolated, loopback-only network namespace by
default. Set namespace_requires_network to true on an action that needs
network access. The action keeps its filesystem, process, mount, UTS, and IPC
isolation, but shares the worker’s network namespace. Omit the property for
actions that do not need network access.
Custom worker pools
Named worker pools let actions select a worker machine type and custom base image. Namespace creates a pool when its first action is queued, starts workers for it on demand, and routes only actions that name that pool to those workers. Actions without a pool use the workspace’s default workers. To use custom worker pools, define each pool as a Bazel execution platform. The platform’sexec_properties describe the properties of the pool. A constraint
value then lets targets select that execution platform with
exec_compatible_with:
--extra_execution_platforms to your project bazelrc instead of
passing it on every invocation.
The machine type uses the format <os>/<arch>:<cpu>x<memory>. For example,
linux/amd64:16x64 selects a Linux AMD64 worker with 16 vCPUs and 64 GB of
memory. See Machine Shapes for
supported CPU and memory configurations.
The following execution properties define a pool:
Every execution platform that uses the same pool name must provide the same pool
definition. The scheduler rejects an action if its machine type or worker image
conflicts with the pool’s existing definition.
Custom worker base images
By default, actions run using one of Namespace’s managed worker images. If your actions need extra tools, libraries, or a specific base environment, you can run them inside your own container image instead. Custom images are selected per action through the standard Bazelcontainer-image execution property.
A few requirements apply:
- The image reference must be pinned to an immutable digest
(
repo@sha256:...). Tags are rejected. - The image must be optimized before it can be used. Namespace converts the image into a fast-booting disk variant.
- The worker image must be hosted in the Namespace container registry
nscr.io. - Custom images are supported on Linux workers only.
Build, push, and optimize a custom image
Build and push your image
Write a Already have an image elsewhere? Use
Dockerfile that starts from any Linux base and adds the tools your
actions need. Authenticate against nscr.io with
nsc docker login, then build and push it
with nsc build for the worker architecture
(linux/amd64 or linux/arm64):nsc base-image upload to pull it and
push it into your nscr.io registry instead:Pin it to an immutable digest
The scheduler requires a digest, not a tag. Resolve the digest your push produced:Use that
repo@sha256:<digest> reference everywhere below.Optimize the image
Optimize the pinned image with
You only need to optimize a given digest once. Pushing a new image with a new digest requires optimizing that new digest.With a runner profile, append it to the profile name:With a machine label, pass it through the See
Configuring Features and Overrides
for the full syntax of feature settings, and
Access Level
for restricting what a runner can do.This grant is only needed when optimizing from a GitHub Actions job. Running
nsc base-image optimize. This step blocks until the optimized variant is ready:Optimizing a base image from a GitHub Actions job requires the job to run with additional permission grants. Pass the
baseimage:*:* grant as a permissions.additional_grant feature setting on the runner.namespace-features: label instead:nsc base-image optimize from a local machine outside of Namespace does not
require it.If you run a build against an image that has not been optimized yet, the scheduler rejects the affected actions with an error telling you the image is not optimized. Run
nsc base-image optimize for that digest.Use the custom image
Set thecontainer-image execution property on a specific target or platform so
only those actions run with the custom worker image:
docker:// scheme prefix is optional. To apply an image through a custom
worker pool instead, set namespace_pool_worker_image as described in
Custom worker pools.
Run preparation scripts at worker startup
A custom worker image can ship preparation scripts that run once before the worker starts handling any actions. These hooks handle setup that must run on every worker boot, such as mounting an external/nix store or seeding caches.
Place executable files in /etc/namespace/prepare.d inside your image. On
startup, the worker runs every executable file in that directory in lexical
order (e.g. 10-mount.sh before 20-warmup.sh). Non-executable files and
subdirectories are skipped.
Preparation scripts are critical: they run at the very start, and if any script exits non-zero the worker fails to start and handles no work.
Observability
Namespace records every invocation that runs through remote execution. Inspect them from the Bazel invocations page, or from the CLI withnsc bazel invocation list and
nsc bazel invocation report.
Reports carry worker assignment and timing, queue times, and hydration times
alongside the usual action and target data, which makes them the place to look
when a build fails for a reason Bazel cannot see.
See Bazel observability for the full workflow,
including how to analyze a report with an agent.
Future reports will also include operation joins, which indicate whether an
invocation joins action invocations from other invocations, and hot or warm
cache information.
Current caveats
Remote Execution has the following current limitations:- Action isolation within macOS workers is not available yet.