---
url: /en/build/build-node.md
description: >
  Explains how to configure build node selection in Cloud Native Build pipelines
  for the PAAS distribution, including runner.tags for node selection,
  runner.cpus for CPU configuration, and how administrators can add custom build
  nodes via System Runner.
---
Cloud Native Build dispatches build tasks to various build nodes for execution,
using the specified Docker image as the build environment.

## Configuration Method

Use `pipeline.runner.tags` to select build nodes and
`pipeline.runner.cpus` to configure the maximum number of CPU cores required.

Administrators can refer to the [System Runner Configuration](../../paas/system-runner.md)
to add build nodes and configure default tags.

Users may omit `tags` to use the default build node. For specific architectures like `arm64/v8`,
administrators can add build nodes of the corresponding architecture and configure tags.

**Use the default node** (omit `tags`):

```yaml title=".cnb.yml"
main:
  push:
    - stages:
        - name: uname
          script: uname -a
```

**Use an `arm64/v8` node**:

```yaml title=".cnb.yml"
main:
  push:
    - runner:
        tags: cnb:arch:arm64:v8
      stages:
        - name: uname
          script: uname -a
```

## Using Organization Self-Hosted Build Nodes

Use `pipeline.runner.namespace` to schedule pipelines onto self-hosted build nodes attached to your organization.

Setting `namespace: group` uses the self-hosted build nodes attached to the **root organization**
that owns the current repository. When omitted, the platform's default scheduling is used.

When `namespace: group` is set, `runner.tags` is **required** and is used to match nodes within the organization.

```yaml title=".cnb.yml"
main:
  push:
    - runner:
        namespace: group
        tags: my-runner
      stages:
        - name: build
          script: echo "running on self-hosted runner"
```

## Root-Organization Custom Runners

In addition to system-administrator-managed build nodes, the platform also allows
**root-organization administrators** to attach their own Mac, Windows and Linux build machines,
providing dedicated capacity for use cases such as iOS builds, Windows desktop packaging,
or Linux ARM server builds.

### Prerequisites

1. The **system administrator** has enabled `Allow Custom Runners` under
   `Admin Console / System Management / Cloud Native Build / Custom Runner`.
2. The **root-organization administrator** has added a Runner under
   `Root Organization / Organization Settings / Build Nodes`, and the node status is `Online`.

### Adding and Connecting a Build Machine

1. Open `Organization Settings / Build Nodes` of the root organization, click `+ Add Runner`,
   fill in the name and tags, and save.
2. The new node starts in the `Offline` state. Click the `Connection Guide` button at the end of the row;
   the dialog shows the node's `SELF_HOSTED_ID` and a one-click setup script.
3. Run the script for the matching platform (Mac or Windows) on the target build machine.
   The node turns `Online` once it successfully connects.

For script details, configuration directories, and common commands, refer to
[System-Level Runner Integration](../../paas/system-runner.md#self-hosted-runner-onboarding).
The Connection Guide dialog already injects the current `SELF_HOSTED_ID` for you,
so no manual replacement is required.

### Using It in `.cnb.yml`

Once the node is online and enabled, schedule pipelines onto it via
`runner.namespace: group` plus `runner.tags`.
`tags` must be a **subset** of the tags declared on the node
(an AND match — every tag listed must appear on the node).
For example, when the node is tagged `[mac, arm64, xcode15]`, using `tags: [mac, arm64]` will match.

#### Mac Node Example

```yaml title=".cnb.yml"
main:
  push:
    - runner:
        # Use a self-hosted runner under the root organization the current repo belongs to
        namespace: group
        # Each listed tag must be present on the node's labels (node labels form a superset)
        # e.g. when the node is tagged [mac, arm64, xcode15], the following will match
        tags:
          - mac
          - arm64
      stages:
        - name: build-on-mac
          script: |
            # Show system info (verify we are running on a mac node)
            sw_vers
            uname -m
            # Common build tools (print versions if installed; missing ones do not fail the pipeline)
            command -v xcodebuild >/dev/null && xcodebuild -version || echo "xcodebuild not installed"
            command -v brew >/dev/null && brew --version || echo "brew not installed"
```

#### Windows Node Example

```yaml title=".cnb.yml"
main:
  push:
    - runner:
        # Use a self-hosted runner under the root organization the current repo belongs to
        namespace: group
        # Each listed tag must be present on the node's labels (node labels form a superset)
        # e.g. when the node is tagged [windows, win11, msvc2022], the following will match
        tags:
          - windows
      stages:
        - name: build-on-windows
          script: |
            # Show system info (verify we are running on a windows node)
            # Note: on self-hosted Windows runners, stage scripts default to PowerShell.
            # `ver` is a cmd built-in, so invoke it via `cmd /c`.
            cmd /c ver
            systeminfo | findstr /B /C:"OS Name" /C:"OS Version"
            # git is a required dependency for self-hosted windows runners
            git -v
```

#### Linux Node Example

```yaml title=".cnb.yml"
main:
  push:
    - runner:
        # Use a self-hosted runner under the root organization the current repo belongs to
        namespace: group
        # Each listed tag must be present on the node's labels (node labels form a superset)
        # e.g. when the node is tagged [linux, arm64, ubuntu22.04], the following will match
        tags:
          - linux
          - arm64
      stages:
        - name: build-on-linux
          script: |
            # Show system info (verify we are running on a linux node)
            uname -a
            cat /etc/os-release
            # git is a required dependency for self-hosted linux runners
            git --version
```

### Node Scheduling

Unlike system build nodes, which by default rotate among only a few machines,
every enabled root-organization custom runner matching the same set of tags
takes part in the rotation.

### Limitations

* Mac, Windows and Linux build machines are supported. Linux runners **must be
  arm64/aarch64**; for x86\_64/amd64 Linux nodes, use the system-administrator-side
  [System-Level Runner Integration](../../paas/system-runner.md).
* The custom build machine must be able to **reach the CNB site**
  (for node registration, heartbeat reporting, pulling pipeline tasks, and uploading logs/artifacts).
  If the machine sits on an internal network, make sure the required egress policy is in place.
* Custom Runners do not enable Docker by default; build scripts run directly on the host. As a result:
  * `runner.cpus` has **no effect**
    (resource limits are enforced via Docker cgroups; without Docker, the full host capacity is available).
  * Docker-image-based build environments (`pipeline.docker.image`, etc.) are not effective.
  * `OverlayFS` is unavailable, so second-read clones automatically fall back to plain `git clone`.
* Custom Runners are **for Cloud Native Build only** and cannot be used for Workspaces (remote development) tasks.
* When a pipeline targets this Runner and the picked node is temporarily
  unavailable (offline, temporarily disabled, or resource usage has reached
  the limits configured by the node administrator, e.g. CPU / memory,
  concurrent pipeline count), the system automatically tries to re-allocate
  to another available node. The pipeline fails if no other available node
  can be assigned.
