One of the great advantages of GitHub Actions is its ability to automate validation flows tailored to your project structure. And monorepos created with NX are a perfect case in point.
In this article, we will build a GitHub Actions workflow that automatically validates any pull request in an NX monorepo, running lint, tests, and compilation only on the affected projects. This allows us to speed up CI, reduce noise, and maintain code quality without wasting resources.
π― What is the purpose of this workflow?
We want the following actions to be performed every time a pull request is opened:
- Detect which parts of the monorepo have been affected
- Run lint only on those parts
- Run the relevant tests
- Compile the affected packages or applications
This ensures that only necessary tasks are executed and that errors are detected as soon as possible β something that is key in monorepos of a certain size.
𧬠General structure of the workflow
Below, I will show you the complete content of the workflow that we are going to analyze:
name: NX Pull request verify
on:
pull_request: {}
jobs:
verify:
name: verify
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "22"
- name: Install dependencies
run: npm install
- name: Run lint
run: npx nx affected --target=lint --head=HEAD --base=origin/main
- name: Run tests
run: npx nx affected --target=test --head=HEAD --base=origin/main
- name: Build package
run: npx nx affected --target=build --head=HEAD --base=origin/main
Let's now take a step-by-step look at what each section does.
π οΈ What does each step involve?
on: pull_request
This section indicates that the workflow will run every time a pull request is opened, updated, or reopened. It is the most common trigger in CI flows for collaborative teams.
uses: actions/checkout@v4
This step downloads the code from the repository so that it is available in the runner.
π Tip: You can configure this step to make a shallow clone or bring in specific branches, but the default configuration is usually sufficient.
uses: actions/setup-node@v4
Here we define the version of Node.js that will be used in the runner (v22 in this case). This ensures consistency between developers and CI.
Some additional useful options:
- cache: βnpmβ: speeds up the installation of dependencies
- check-latest: true: forces the latest available version of semver
- registry-url: useful if you are going to publish packages to NPM
run: npm install
Install the project dependencies. For CI environments, it is recommended to use npm ci
if you have a package-lock.json
, as it is faster and more predictable.
βοΈ The specific logic of NX
The most interesting thing about this workflow is that it uses the nx affected
command, which allows you to run tasks only on projects affected by the changes introduced in the pull request.
npx nx affected --target=lint
Run linter only on modified projects.
npx nx affected --target=test
Run the corresponding tests only on those projects.
npx nx affected --target=build
Only compile the packages or applications that have been affected.
This selective approach is one of the great advantages of NX, and its integration with GitHub Actions makes it especially powerful in large monorepos.
π§ What do --head and --base mean?
These two options tell NX which branches to compare the changes against to determine what has been affected:
- --base=origin/main: specifies the reference branch (e.g., main)
- --head=HEAD: refers to the current commit of the PR
NX will calculate which projects have been modified between main and the HEAD of the pull request, and will only execute the necessary tasks on them.
β Final result: Intelligent and efficient CI
This workflow allows each pull request to go through a well-defined validation system, without the need to run unnecessary tasks across the entire repository.
Key advantages:
- Saves execution time in CI
- Less resource consumption
- Early validation of errors in critical code
- Improves the experience for external contributors
π‘ Ideas for extending this workflow
Some ideas to improve it even further:
- Add caching with actions/cache
- Run validation on multiple versions of Node using matrix
- Include automatic comments in the pull request with results
- Split jobs in parallel (lint, test, build)
But we'll leave that for another article! π
π Would you prefer a visual way to build this workflow?
If you don't want to write this YAML by hand or prefer to focus on logic rather than syntax, you can use OctoLab:
- β Step-by-step visual editor
- β Smart fields for NX actions
- β Real-time YAML preview
- β Automatic validations
- β Copy, download, and use instantly
π Try it out at: https://www.octolab.app
π§΅ Conclusion
Well-managed NX monorepos require efficient automation, and this workflow is an excellent way to ensure quality without wasting resources. With tools like GitHub Actions and approaches like nx affected
, you can take your project's CI to the next level.
And if you want to do all this without fighting with YAML, you know where to find help π€.
Top comments (0)