Remote caching speeds up your CI, but you can go even faster by skipping unnecessary tasks altogether.
Most pull requests change a few files, so CI should only run the tasks those files affect. nx affected selects and runs only the tasks that need to run for the given changes.
For example, say a web app depends on a ui library, and your pull request only updates the unit test file button.spec.ts in ui. nx affected runs ui:test and skips ui:build, since spec files aren't an input to the production build. It skips web:build and web:test too, because the spec file for ui isn't an input to either.
How Nx selects affected tasks
Section titled “How Nx selects affected tasks”Run nx affected with the targets you want, particularly on CI:
nx affected -t <targets>For the web and ui example, run the affected build and test tasks:
nx affected -t build testNx then:
- Uses Git to find the files your branch changed, for example
libs/ui/src/button.spec.ts. - Selects each
buildandtesttask whose inputs include a changed file. - Selects the tasks that read the outputs of a selected task, like a
web:buildthat reads theuibuild output. - Runs the selected tasks and the tasks they depend on, restoring unchanged dependencies from the cache.
Only ui:test reads the spec file. In this nx.json, production is a named input that leaves out spec files, and ^ reads an input from a project's dependencies:
{ "namedInputs": { "production": ["{projectRoot}/**/*", "!{projectRoot}/**/*.spec.ts"] }, "targetDefaults": { "build": { "inputs": ["production", "^production"] }, "test": { "inputs": ["{projectRoot}/**/*", "^production"] } }}To see the affected tasks in the task graph without running them, pass --graph:
nx affected -t build test --graphConfigure affected on CI
Section titled “Configure affected on CI”The affected command takes a base and head commit. The default base is your main branch, and the default head is your current file system. This is generally what you want when developing locally, but in CI, you need to customize these values.
nx affected -t build --base=origin/main --head=$PR_BRANCH_NAME # where PR_BRANCH_NAME is defined by your CI systemnx affected -t build --base=origin/main~1 --head=origin/main # rerun what is affected by the last commit in mainYou can also set the base and head SHAs as environment variables:
NX_BASE=origin/main~1NX_HEAD=origin/mainThe recommended approach is to set the base SHA to the latest successful commit on the main branch. This ensures that all changes since the last successful CI run are accounted for.
The nrwl/nx-set-shas action uses the GitHub API to find the last successful workflow run on main and sets NX_BASE and NX_HEAD, so nx affected needs no extra flags.
steps: - uses: actions/checkout@v7 with: fetch-depth: 0 filter: tree:0 - run: npm ci - uses: nrwl/nx-set-shas@v5 - run: npx nx affected -t lint test buildfetch-depth: 0 is required. Without the full Git history, there is no base commit to compare against.
The nx/set-shas command from the Nx Orb finds the last successful pipeline on main and sets NX_BASE and NX_HEAD, so nx affected needs no extra flags.
version: 2.1
orbs: nx: nrwl/nx@1.7.0
jobs: main: docker: - image: cimg/node:lts-browsers steps: - checkout - run: npm ci - nx/set-shas: main-branch-name: 'main' - run: npx nx affected -t lint test buildGitLab has no equivalent action. Set NX_BASE and NX_HEAD from GitLab's predefined variables instead. Merge request pipelines compare against the merge request's diff base, and pushes to main compare against the previous commit on the branch.
image: node:22
CI: only: - main - merge_requests script: - npm ci - export NX_HEAD=$CI_COMMIT_SHA - export NX_BASE=${CI_MERGE_REQUEST_DIFF_BASE_SHA:-$CI_COMMIT_BEFORE_SHA} - npx nx affected -t lint test buildFor other CI providers (Jenkins, Azure Pipelines, Bitbucket), see our guides to get the last successful CI run for your CI provider.
Understanding why something is affected
Section titled “Understanding why something is affected”Use the --explain flag to show why tasks are affected. Nx prints the explanation, then exits without running anything. Say your branch changes libs/ui/src/index.ts instead of the spec file:
nx affected -t build --explain NX 2 out of 2 build tasks are affected
Changing 1 file touches 2 build tasks. Pass --verbose to list each with its reasons.
libs/ui/src/index.ts: - ui:build - web:build--explain explains task selection, so it needs targets passed with -t. Without them, or with affected.legacy set, it stops with an error.
Pass --explain=stdout for the data as JSON, or --explain=reasons.json to write it to a file. nx show projects --affected -t build --explain works the same way.
Best paired with remote caching and distribution
Section titled “Best paired with remote caching and distribution”nx affected can still select a lot of work:
- A change to a project most of the workspace depends on, or to an input every task shares, selects most tasks.
- Every push to a pull request is compared with the same base commit on
main, so each push selects the same tasks again.
Remote caching replays the selected tasks whose inputs didn't change since an earlier run, so a later push only runs what its new commits affect. With Ultracache, Nx selects tasks from the files each task read in CI instead of its declared inputs, so unused files don't select tasks and reads missing from inputs aren't overlooked. Distributed task execution spreads the tasks that do run across machines.
Ignoring files from affected commands
Section titled “Ignoring files from affected commands”Nx provides two methods to exclude glob patterns (files and folders) from nx affected -t <targets>:
- Glob patterns defined in your
.gitignorefile are ignored. - Glob patterns defined in an optional
.nxignorefile are ignored.
Lock file changes
Section titled “Lock file changes”By default, a change to your package manager's lock file affects every task. To limit it to the tasks of projects whose resolved dependencies changed, set projectsAffectedByDependencyUpdates to "auto" in nx.json.
Not using git
Section titled “Not using git”If you aren't using Git, you can pass --files to any affected command to indicate what files have been changed.
Nx 23 and earlier use project-based affected
Section titled “Nx 23 and earlier use project-based affected”Nx 23 and earlier use project-based affected: a change to a project runs every task of that project and of every project that depends on it. Running nx migrate to Nx 24 keeps that behavior in existing workspaces by setting affected.legacy to true in nx.json:
{ "affected": { "legacy": true }}Remove the setting, or set it to false, to use task-based affected. NX_LEGACY_AFFECTED overrides it for one invocation: true uses project-based affected and false uses task-based. Set it for the whole CI job, so nx show projects --affected -t test and nx affected -t test in the same script see the same affected set. nx graph --affected always shows projects.