Launch Templates

A launch template defines the setup steps Nx Agents will run before running tasks. A custom launch template isn't required to use Nx Agents. Nx Cloud provides several pre-built launch templates for common use-cases. You can view available templates in the nx-cloud-workflows repository.

Getting Started with Custom Launch Templates

The easiest way to create a new custom launch template is to modify one of the pre-built ones. To do that, create a file in the .nx/workflows folder and copy one of the pre-built templates. You can name the file any way you want (e.g., agents.yaml) and customize the steps as needed.

Launch Template Structure

launch-templates

A map of launch template configurations. This value is required.

.nx/workflows/agents.yaml
1launch-templates: 2

launch-templates.<template-name>

The name of your custom launch template. This name is used via --distribute-on="<# of agents> <template-name>" when starting the ci run. Supports one to many uniquely named launch templates. Multiple launch templates can be useful for setting up different toolchains (rust, java, node versions) or resources classes for your workspace needs.

.nx/workflows/agents.yaml
1launch-templates: 2 template-one: 3 template-two: 4
1nx-cloud start-ci-run --distribute-on="3 template-one" 2

launch-templates.<template-name>.resource-class

A launch template's resource-class defines the memory and vCPUs available to each agent machine.

.nx/workflows/agents.yaml
1launch-templates: 2 template-one: 3 resource-class: 'docker_linux_amd64/medium' 4

The following resource classes are available:

  • docker_linux_amd64/small
  • docker_linux_amd64/medium
  • docker_linux_amd64/medium+
  • docker_linux_amd64/large
  • docker_linux_amd64/large+
  • docker_linux_amd64/extra_large
  • docker_linux_amd64/extra_large+
  • docker_linux_arm64/medium
  • docker_linux_arm64/large
  • docker_linux_arm64/extra_large
  • windows/medium

See their detailed description and pricing at nx.dev/pricing.

launch-templates.<template-name>.image

A launch template's image defines the available base software for the agent machine.

.nx/workflows/agents.yaml
1launch-templates: 2 template-one: 3 image: 'ubuntu22.04-node20.11-v9' 4

Nx Cloud provides the following images:

Changes added in previous images are included in newer images unless otherwise denoted Images also have go 1.22 installed

  • ubuntu22.04-node20.11-v5

    • added elevated permission access via sudo
  • ubuntu22.04-node20.11-v6

  • ubuntu22.04-node20.11-v7

    • added java version 17
  • ubuntu22.04-node20.11-v9

  • windows-2022

Note: Windows-based images can only run on Windows-based resource classes.

Enterprise accounts can use custom images.

launch-templates.<template-name>.env

A launch template's env defines a map of environment variable names and values to be available within all steps of the specific launch template.

.nx/workflows/agents.yaml
1launch-templates: 2 template-one: 3 env: 4 MY_ENV_VAR: 'my-var-value' 5

launch-templates.<template-name>.init-steps

A launch template's init-steps defines the series of steps to perform before an Nx Agent runs. Without a defined init-steps the Nx Agent is unable to process any tasks.

Typical init-steps perform actions such as checking out your workspace source code and installing any necessary dependencies. Any extra setup your workspace needs to run should be defined as an init-step. Once all steps run successfully, the agent machine will inform Nx Cloud that it is ready to accept tasks.

.nx/workflows/agents.yaml
1launch-templates: 2 template-one: 3 init-steps: 4

launch-templates.<template-name>.init-steps[*].name

An init-step's name is the label that will be reflected in the Nx Cloud UI. name can be used in conjunction with uses and script

.nx/workflows/agents.yaml
1launch-templates: 2 template-one: 3 init-steps: 4 - name: 'My Helpful Step Name' 5

launch-templates.<template-name>.init-steps[*].uses

When defined, specifies an existing step file to be used. Cannot be used when script is also defined

You can find the list of Nx Cloud reusable steps here. If you cannot find a reusable step that suits your needs, you can create your own custom steps.

.nx/workflows/agents.yaml
1launch-templates: 2 template-one: 3 init-steps: 4 - uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/checkout/main.yaml' 5 - name: 'Install Node Modules' 6 uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/install-node-modules/main.yaml' 7

launch-templates.<template-name>.init-steps[*].script

When defined, allows an inline script to be run. Cannot be used when uses is also defined

.nx/workflows/agents.yaml
1launch-templates: 2 template-one: 3 init-steps: 4 - name: 'Print Node Version and PATH' 5 script: | 6 node -v 7 echo $PATH 8

launch-templates.<template-name>.init-steps[*].env

An init-step's env is similar to the launch-template.<template-name>.env, except the environment variable map is scoped for the current step only.

.nx/workflows/agents.yaml
1launch-templates: 2 template-one: 3 init-steps: 4 - name: 'Print Env' 5 env: 6 MY_STEP_ENV: 'step-env-var' 7 script: | 8 echo $MY_STEP_ENV # prints "step-env-var" 9

launch-templates.<template-name>.init-steps[*].inputs

An init-step's inputs is defined by the step file in the launch-template.<template-name>.init-steps[*].uses property. Refer to the step file's documentation for specific inputs.

Validation can also be done to validate the step against the step file's defined inputs

.nx/workflows/agents.yaml
1launch-templates: 2 template-one: 3 init-steps: 4 - name: Restore Node Modules Cache 5 uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/cache/main.yaml' 6 inputs: 7 key: 'package-lock.json|yarn.lock|pnpm-lock.yaml' 8 paths: | 9 ~/.npm 10 # or ~/.cache/yarn 11 # or .pnpm-store 12 base-branch: 'main' 13

launch-templates.<template-name>.group-name

You can define "step groups" that run in parallel. This can be useful for taking better advantage of the available CPUs of your chosen resource class. In the example below, we can run NPM Install and install the Rust dependencies in parallel, because they do not depend on each other and they write to different places on the filesystem. Running them in parallel can reduce agent startup time by up to 2 minutes, which can add up to a lot of compute time savings over the month.

⚠️ Tips for using parallel steps:

  • don't assume everything can be run in parallel
    • you'll notice below we had to run playwright install after the parallel group, as it was likely writing to the same locations and fighting for similar resources to npm install
    • experiment with different parallel groups and measure startup times until you land on the most optimal config for your use-case
  • write to PATH once
    • multiple parallel processes can overwrite each other's changes if they write to the same >> $NX_CLOUD_ENV location
    • below, we only update the PATH variable once at the end echo "PATH=$CARGO_PATH:$POETRY_PATH:$PATH" >> $NX_CLOUD_ENV
.nx/workflows/agents.yaml
1launch-templates: 2 template-one: 3 init-steps: 4 - group-name: Install Dependencies 5 parallel: true 6 # all the below steps will start at the same time and run in parallel 7 steps: 8 - name: Install Rust 9 script: | 10 curl --proto '=https' --tlsv1.3 https://sh.rustup.rs -sSf | sh -s -- -y 11 source "~/workspace/.cargo/env" 12 # we write the CARGO_PATH now so that it can be set in the "Start Services" step below 13 echo "CARGO_PATH=~/workspace/.cargo/bin" >> $NX_CLOUD_ENV 14 rustc --version 15 rustup target add wasm32-wasip1-threads 16 cargo fetch 17 cargo check --locked 18 - name: NPM Install 19 uses: 'nrwl/nx-cloud-workflows/main/workflow-steps/install-node-modules/main.yaml' 20 - name: Install Poetry 21 script: | 22 curl -sSL https://install.python-poetry.org | python3 - 23 # we write the POETRY_PATH now so that it can be set in the "Start Services" step below 24 export POETRY_PATH="/home/workflows/.local/bin" 25 export PATH="$POETRY_PATH:$PATH" 26 echo "POETRY_PATH=$POETRY_PATH" >> $NX_CLOUD_ENV 27 poetry --version 28 poetry install 29 - name: Install Localstack 30 script: | 31 curl --output localstack-cli-3.7.0-linux-amd64-onefile.tar.gz --location https://github.com/localstack/localstack-cli/releases/download/v3.7.0/localstack-cli-3.7.0-linux-amd64-onefile.tar.gz 32 sudo tar xvzf localstack-cli-3.7.0-linux-*-onefile.tar.gz -C /usr/local/bin 33 # because both playwright and "npm install" use NPM and write to a lot of the same places on the filesystem, it would be slower to run them both in parallel 34 # so we run playwright after the parallel group above 35 - name: Install Playwright 36 script: npx playwright install --with-deps 37 - name: Start services 38 script: | 39 # we create the PATH here 40 echo "PATH=$CARGO_PATH:$POETRY_PATH:$PATH" >> $NX_CLOUD_ENV 41 npm run start-docker-services 42

We can also group steps and run them serially. This is actually the default behaviour when you don't set parallel: true for a group.

This can be useful if we have a set of quick enough steps, such as restoring from cache, where we don't need to optimise for speed, and instead we just want them grouped together logically. The below cache steps will also be collapsed together in the Agents UI, making the config look cleaner:

1- group-name: Restore Cache 2 steps: 3 - name: Restore Node Modules Cache 4 uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/cache/main.yaml' 5 inputs: 6 key: 'package-lock.json' 7 paths: | 8 ~/.npm 9 base-branch: 'main' 10 - name: Restore Browser Binary Cache 11 uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/cache/main.yaml' 12 inputs: 13 key: 'package-lock.json|"browsers"' 14 paths: | 15 '~/.cache/Cypress' 16 base-branch: 'main' 17

Full Example

This is an example of a launch template using all pre-built features:

./nx/workflows/agents.yaml
1common-init-steps: &common-init-steps 2 - name: Checkout 3 # using a reusable step in an external GitHub repo, 4 # this step is provided by Nx Cloud: https://github.com/nrwl/nx-cloud-workflows/tree/main/workflow-steps 5 uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/checkout/main.yaml' 6 # group these steps together as they related (it doesn't change anything functionally, but it helps with organising your steps as they will be collapsed together in the UI) 7 - group-name: Restore Cache 8 steps: 9 - name: Restore Node Modules Cache 10 uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/cache/main.yaml' 11 # the cache step requires configuration via env vars 12 # https://github.com/nrwl/nx-cloud-workflows/tree/main/workflow-steps/cache#options 13 inputs: 14 key: 'package-lock.json|yarn.lock|pnpm-lock.yaml' 15 paths: | 16 ~/.npm 17 # or ~/.cache/yarn 18 # or .pnpm-store 19 base-branch: 'main' 20 - name: Restore Browser Binary Cache 21 uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/cache/main.yaml' 22 inputs: 23 key: 'package-lock.json|yarn.lock|pnpm-lock.yaml|"browsers"' 24 paths: | 25 '~/.cache/Cypress' 26 base-branch: 'main' 27 - name: Install Node Modules 28 uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/install-node-modules/main.yaml' 29 - name: Install Browsers (if needed) 30 uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/install-browsers/main.yaml' 31 # You can also run a custom script to configure various things on the agent machine 32 - name: Run a custom script 33 script: | 34 git config --global user.email test@test.com 35 git config --global user.name "Test Test" 36 # You can also set any other env vars to be passed to the following steps 37 # by setting their value in the `$NX_CLOUD_ENV` file. 38 # Most commonly for redefining PATH for further steps 39 - name: Setting env 40 script: | 41 # Update PATH with custom value 42 echo "PATH=$HOME/my-folder:$PATH" >> $NX_CLOUD_ENV 43 - name: Print path from previous step 44 # will include my-folder 45 script: echo $PATH 46 - name: Define env var for a step 47 env: 48 MY_ENV_VAR: 'env-var-for-step' 49 # will print env-var-for-step 50 script: echo $MY_ENV_VAR 51 # after you're last step Nx Agents will start accepting tasks to process 52 # no need to manually start up the agent yourself 53 54launch-templates: 55 # Custom template name, the name is referenced via --distribute-on="3 my-linux-medium-js" 56 # You can define as many templates as you need, commonly used to make different sizes or toolchains depending on your workspace needs 57 my-linux-medium-js: 58 # see the available resource list below 59 resource-class: 'docker_linux_amd64/medium' 60 # see the available image list below 61 image: 'ubuntu22.04-node20.11-v9' 62 # Define environment variables shared among all steps 63 env: 64 MY_ENV_VAR: shared 65 # list out steps to run on the agent before accepting tasks 66 # the agent will need a copy of the source code and dependencies installed 67 # note we are using yaml anchors te reduce duplication with the below launch-template (they have the same init-steps) 68 init-steps: *common-init-steps 69 70 # another template which does the same as above, but with a large resource class 71 # You're not required to define a template for every resource class, only define what you need! 72 my-linux-large-js: 73 resource-class: 'docker_linux_amd64/large' 74 image: 'ubuntu22.04-node20.11-v9' 75 env: 76 MY_ENV_VAR: shared 77 # note we are using yaml anchors te reduce duplication with the above launch-template (they have the same init-steps) 78 init-steps: *common-init-steps 79 80 # template that installs rust 81 my-linux-rust-large: 82 resource-class: 'docker_linux_amd64/large' 83 image: 'ubuntu22.04-node20.11-v9' 84 init-steps: 85 - name: Checkout 86 uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/checkout/main.yaml' 87 - name: Restore Node Modules Cache 88 uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/cache/main.yaml' 89 inputs: 90 key: 'package-lock.json|yarn.lock|pnpm-lock.yaml' 91 paths: | 92 ~/.npm 93 # or ~/.cache/yarn 94 # or .pnpm-store 95 base-branch: 'main' 96 - name: Install Node Modules 97 uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/install-node-modules/main.yaml' 98 - name: Install Rust 99 script: | 100 curl --proto '=https' --tlsv1.3 https://sh.rustup.rs -sSf | sh -s -- -y 101 source "$HOME/.cargo/env" 102 rustup toolchain install 1.70.0 103 # persist cargo bin into PATH 104 echo "PATH=$HOME/.cargo/bin:$PATH" >> $NX_CLOUD_ENV 105

These templates can be used by passing the number of agents desired, and the template name via --distribute-on when starting your CI run.

1nx-cloud start-ci-run --distribute-on="4 my-linux-medium-js" 2
1nx-cloud start-ci-run --distribute-on="4 my-linux-large-js" 2
1nx-cloud start-ci-run --distribute-on="4 my-linux-large-rust" 2

Validating Launch Templates

Commit before Validation

Before Nx Cloud can validate your custom templates, you must first commit any changes to these templates to your source control repository. Running the validation command from a CI is the recommended approach.

After creating your custom launch template, it's recommended to validate it. This ensures that all necessary fields within the launch template and all respective inputs within each step are appropriately defined.

To do this, run the nx-cloud validate command, with the path to the launch template:

nx-cloud validate --workflow-file=./.nx/workflows/agents.yaml

Pass Environment Variables to Agents

If you need to send environment variables to agents, you can use the --with-env-vars flag on the nx-cloud start-ci-run command. You can pass a specific list of environment variables like this:

1nx-cloud start-ci-run --distribute-on="8 linux-medium-js" --with-env-vars="VAR1,VAR2" 2

Pass Values Between Steps

If you need to pass a value from one step to another step, such as assigning the value to an existing or new environment variable. You can write to the NX_CLOUD_ENV environment file.

Commonly used for redefining the PATH or setting options for tooling.

./nx/workflows/agents.yaml
1launch-templates: 2 my-template-name: 3 init-steps: 4 - name: Set PATH 5 script: echo "PATH=$HOME/.cargo/bin:$PATH" >> $NX_CLOUD_ENV 6 - name: Check PATH 7 script: | 8 # now contains $HOME/.cargo/bin 9 echo $PATH 10 # can invoke cargo directly because it's in the PATH now. 11 cargo --version 12

Private NPM Registry

If your project consumes packages from a private registry, you'll have to set up an authentication step in a custom launch template and authenticate like you normally would, usually this is via a .npmrc or .yarnrc file. You can pass the auth token from your main agent, so it's available to the agent machines.

.nx/workflows/agents.yaml
1launch-templates: 2 my-linux-medium-js: 3 resource-class: 'docker_linux_amd64/medium' 4 image: 'ubuntu22.04-node20.11-v9' 5 init-steps: 6 - name: Checkout 7 uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/checkout/main.yaml' 8 - name: Auth to Registry 9 script: | 10 # create .npmrc with @myorg scoped packages pointing to GH npm registry 11 echo "@myorg:registry=https://npm.pkg.github.com" >> .npmrc 12 echo "//npm.pkg.github.com/:_authToken=${SOME_AUTH_TOKEN}" >> .npmrc 13 - name: Install Node Modules 14 uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/install-node-modules/main.yaml' 15

Pass SOME_AUTH_TOKEN via --with-env-vars

1# this assumes SOME_AUTH_TOKEN is already defined on the main agent 2nx-cloud start-ci-run --distribute-on="5 my-linux-medium-js" --with-env-vars="SOME_AUTH_TOKEN" 3

Custom Node Version

Nx Agents come with node LTS installed. If you want to use a different version, you can add a step to install the desired node version.

Nx Cloud provides a pre-built step to install a custom node version within your workflow. This step is available as of v4 of the workflow steps and requires the minimum image version to be ubuntu22.04-node20.11-v9.

.nx/workflows/agents.yaml
1launch-templates: 2 node-21: 3 resource-class: 'docker_linux_amd64/medium' 4 # note the image version of v9, 5 # earlier versions of the base image will not work 6 image: 'ubuntu22.04-node20.11-v9' 7 init-steps: 8 - name: Checkout 9 uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/checkout/main.yaml' 10 - name: Install Node 11 # note the step is only released as of v4 of the workflow steps 12 uses: 'nrwl/nx-cloud-workflows/v5/workflow-steps/install-node/main.yaml' 13 inputs: 14 # can omit value if a '.nvmrc' file is within the root of the repo 15 node_version: '21' 16

Specific Package Manager Version

Nx Agents have corepack enabled by default, allowing you to define the yarn or pnpm version via the package.json.

package.json
1{ 2 "packageManager": "yarn@4.1.1" 3} 4
Supported Package Managers

Currently, corepack only supports yarn or pnpm as package managers. If you need to use a specific npm version, you will need to create a custom launch template and install the specific npm version, i.e. npm install -g npm@<version>

Installing Packages on Nx Agents

You can use apt to install popular linux packages. This is helpful in streamlining setting up various toolchains needed for your workspace.

For example, you can install the GitHub CLI on the agents if needed.

./nx/workflows/agents.yaml
1launch-templates: 2 my-linux-medium-js: 3 resource-class: 'docker_linux_amd64/medium' 4 image: 'ubuntu22.04-node20.11-v9' 5 init-steps: 6 - name: Install Extras 7 script: | 8 sudo apt install gh unzip zip -y 9
Installing without apt

If you're trying to install a package that isn't available on apt, check that packages install steps for Debian base linux. Usually there are a handful of installation scripts that can be used similar to nvm

Dynamic Changesets

NxCloud can calculate how big your pull request is based on how many projects in your workspace it affects. You can then configure Nx Agents to dynamically use a different number of agents based on your changeset size.

Here we define a small, medium and large distribution strategy:

.nx/workflows/dynamic-changesets.yaml
1distribute-on: 2 small-changeset: 3 linux-medium-js 3 medium-changeset: 8 linux-medium-js 4 large-changeset: 12 linux-medium-js 5

Then you can pass the path to the file to the --distribute-on parameter.

1nx-cloud start-ci-run --distribute-on=".nx/workflows/dynamic-changesets.yaml" 2

Debugging

You can add steps to your template which print information about your workspace, toolchains, or any other needs. Below are some common steps people use for debugging such as running nx commands, printing file contents and/or listing directory contents.

Environment Variables

Exercise caution when printing out environment variables, they will be shown in plain text.

.nx/workflows/agents.yaml
1launch-templates: 2 my-linux-medium-js: 3 resource-class: 'docker_linux_amd64/medium' 4 image: 'ubuntu22.04-node20.11-v9' 5 env: 6 # enable verbose logging for all steps 7 NX_VERBOSE_LOGGING: true 8 init-steps: 9 - name: 'Debug: Print Nx Report' 10 script: | 11 nx report 12 - name: 'Debug: List Directory Contents' 13 script: | 14 echo $HOME 15 ls -la $HOME 16 output_dir=$HOME/dist 17 # if output directory exists list it's contents 18 if [ -d output_dir ]; then 19 ls -la $output_dir 20 else 21 echo "$output_dir does not exist" 22 fi 23 - name: 'Debug: Show File Contents' 24 script: | 25 cat $HOME/.profile 26 - name: 'Debug: Check For Checkout Files' 27 script: | 28 git diff 29 - name: 'Debug: Print Versions' 30 script: | 31 # note if you use yarn and try to run pnpm, corepack might throw an error at you 32 # saying you're using the wrong package manager, in that case just remove the usage of pnpm 33 echo "Versions:" 34 echo "Node: $(node -v)" 35 echo "NPM: $(npm -v)" 36 echo "Yarn: $(yarn -v)" 37 echo "PNPM: $(pnpm -v)" 38 echo "Golang: $(go version)" 39 echo "Java: $(javac --version)" 40 # add any other toolchain you want 41 - name: 'Debug: Print env' 42 script: | 43 # !!! DO NOT RUN THIS IF YOU HAVE PASSWORD/ACCESS TOKENS IN YOUR ENV VARS !!! 44 # this will print your env as plain text values to the terminal 45 env 46 # This is a safer approach to prevent leaking tokens/passwords 47 echo "SOME_VALUE: $SOME_VALUE" 48