Adding Nx to NPM/Yarn/PNPM Workspace

Migrating from Lerna?

Interested in migrating from Lerna in particular? In case you missed it, Lerna v6 is powering Nx underneath. As a result, Lerna gets all the modern features such as caching and task pipelines. Read more on https://lerna.js.org/upgrade.

Nx has first-class support for monorepos. As a result, if you have an existing NPM/Yarn or PNPM-based monorepo setup, you can easily add Nx to get

This is a low-impact operation because all that needs to be done is to install the nx package at the root level and add an nx.json for configuring caching and task pipelines.

Installing Nx

Run the following command to automatically set up Nx:

npx nx@latest init

Running this command will ask you a few questions about your workspace and then set up Nx for you accordingly. The setup process detects tools which are used in your workspace and suggests installing Nx plugins to integrate the tools you use with Nx. Running those tools through Nx will have caching enabled when possible, providing you with a faster alternative for running those tools. You can start with a few to see how it works and then add more with the nx add command later. You can also decide to add them all and get the full experience right away because adding plugins will not break your existing workflow.

The first thing you may notice is that Nx updates your package.json scripts during the setup process. Nx Plugins setup Nx commands which run the underlying tool with caching enabled. When a package.json script runs a command which can be run through Nx, Nx will replace that script in the package.json scripts with an Nx command that has caching automatically enabled. Anywhere those package.json scripts are used, including your CI, will become faster when possible. Let's go through an example where the @nx/next/plugin and @nx/eslint/plugin plugins are added to a workspace with the following package.json.

package.json
1{ 2 "name": "my-workspace", 3 ... 4 "scripts": { 5- "build": "next build && echo 'Build complete'", 6+ "build": "nx next:build && echo 'Build complete'", 7- "lint": "eslint ./src", 8+ "lint": "nx eslint:lint", 9 "test": "node ./run-tests.js" 10 }, 11 ... 12} 13

The @nx/next/plugin plugin adds a next:build target which runs next build and sets up caching correctly. In other words, running nx next:build is the same as running next build with the added benefit of it being cacheable. Hence, Nx replaces next build in the package.json build script to add caching to anywhere running npm run build. Similarly, @nx/eslint/plugin sets up the nx eslint:lint command to run eslint ./src with caching enabled. The test script was not recognized by any Nx plugin, so it was left as is. After Nx has been setup, running npm run build or npm run lint multiple times, will be instant when possible.

You can also run any npm scripts directly through Nx with nx build or nx lint which will run the npm run build and npm run lint scripts respectively. In the later portion of the setup flow, Nx will ask if you would like some of those npm scripts to be cacheable. By making those cacheable, running nx build rather than npm run build will add another layer of cacheability. However, nx build must be run instead of npm run build to take advantage of the cache.

Inferred Tasks

You may have noticed that @nx/next provides dev and start tasks in addition to the next:build task. Those tasks were created by the @nx/next/plugin plugin from your existing Next.js configuration. You can see the configuration for the Nx Plugins in nx.json:

nx.json
1{ 2 "plugins": [ 3 { 4 "plugin": "@nx/eslint/plugin", 5 "options": { 6 "targetName": "eslint:lint" 7 } 8 }, 9 { 10 "plugin": "@nx/next/plugin", 11 "options": { 12 "buildTargetName": "next:build", 13 "devTargetName": "dev", 14 "startTargetName": "start" 15 } 16 } 17 ] 18} 19

Each plugin can accept options to customize the projects which they create. You can see more information about configuring the plugins on the @nx/next/plugin and @nx/eslint/plugin plugin pages.

To view all available tasks, open the Project Details view with Nx Console or use the terminal to launch the project details in a browser window.

nx show project my-workspace --web

Project Details View

my-workspace

ESLint
Next.js

Root: .

Type:library

Targets

  • dev

    Next.js

    next dev

  • eslint:lint

    ESLint

    eslint ./src

    Cacheable
  • next:build

    Next.js

    next build

    Cacheable
  • start

    Next.js

    next start

The project detail view lists all available tasks, the configuration values for those tasks and where those configuration values are being set.

Configure an Existing Script to Run with Nx

If you want to run one of your existing scripts with Nx, you need to tell Nx about it.

  1. Preface the script with nx exec -- to have npm run test invoke the command with Nx.
  2. Define caching settings.

The nx exec command allows you to keep using npm test or npm run test (or other package manager's alternatives) as you're accustomed to. But still get the benefits of making those operations cacheable. Configuring the test script from the example above to run with Nx would look something like this:

package.json
1{ 2 "name": "my-workspace", 3 ... 4 "scripts": { 5 "build": "nx next:build", 6 "lint": "nx eslint:lint", 7 "test": "nx exec -- node ./run-tests.js" 8 }, 9 ... 10 "nx": { 11 "targets": { 12 "test": { 13 "cache": "true", 14 "inputs": [ 15 "default", 16 "^default" 17 ], 18 "outputs": [] 19 } 20 } 21 } 22} 23

Now if you run npm run test or nx test twice, the results will be retrieved from the cache. The inputs used in this example are as cautious as possible, so you can significantly improve the value of the cache by customizing Nx Inputs for each task.

Incrementally Adopting Nx

All the features of Nx can be enabled independently of each other. Hence, Nx can easily be adopted incrementally by initially using Nx just for a subset of your scripts and then gradually adding more.

For example, use Nx to run your builds:

npx nx run-many -t build

But instead keep using NPM/Yarn/PNPM workspace commands for your tests and other scripts. Here's an example of using PNPM commands to run tests across packages

pnpm run -r test

This allows for incrementally adopting Nx in your existing workspace.

Set Up CI for Your Workspace

This tutorial walked you through how Nx can improve the local development experience, but the biggest difference Nx makes is in CI. As repositories get bigger, making sure that the CI is fast, reliable and maintainable can get very challenging. Nx provides a solution.

Connect to Nx Cloud

Nx Cloud is a companion app for your CI system that provides remote caching, task distribution, e2e tests deflaking, better DX and more.

Now that we're working on the CI pipeline, it is important for your changes to be pushed to a GitHub repository.

  1. Commit your existing changes with git add . && git commit -am "updates"
  2. Create a new GitHub repository
  3. Follow GitHub's instructions to push your existing code to the repository

Now connect your repository to Nx Cloud with the following command:

npx nx connect

A browser window will open to register your repository in your Nx Cloud account. The link is also printed to the terminal if the windows does not open, or you closed it before finishing the steps. The app will guide you to create a PR to enable Nx Cloud on your repository.

Once the PR is created, merge it into your main branch.

And make sure you pull the latest changes locally:

git pull

You should now have an nxCloudAccessToken property specified in the nx.json file.

Create a CI Workflow

Use the following command to generate a CI workflow file.

npx nx generate ci-workflow --ci=github

This generator creates a .github/workflows/ci.yml file that contains a CI pipeline that will run the lint, test, build and e2e tasks for projects that are affected by any given PR. Since we are using Nx Cloud, the pipeline will also distribute tasks across multiple machines to ensure fast and reliable CI runs.

The key lines in the CI pipeline are:

.github/workflows/ci.yml
1name: CI 2# ... 3jobs: 4 main: 5 runs-on: ubuntu-latest 6 steps: 7 - uses: actions/checkout@v4 8 with: 9 fetch-depth: 0 10 # This enables task distribution via Nx Cloud 11 # Run this command as early as possible, before dependencies are installed 12 # Learn more at https://nx.dev/ci/reference/nx-cloud-cli#npx-nxcloud-startcirun 13 # Connect your workspace by running "nx connect" and uncomment this 14 - run: npx nx-cloud start-ci-run --distribute-on="3 linux-medium-js" --stop-agents-after="build" 15 - uses: actions/setup-node@v3 16 with: 17 node-version: 20 18 cache: 'npm' 19 - run: npm ci --legacy-peer-deps 20 - uses: nrwl/nx-set-shas@v4 21 # Nx Affected runs only tasks affected by the changes in this PR/commit. Learn more: https://nx.dev/ci/features/affected 22 - run: npx nx affected -t lint test build 23

Open a Pull Request

Commit the changes and open a new PR on GitHub.

git add .

git commit -m 'add CI workflow file'

git push origin add-workflow

When you view the PR on GitHub, you will see a comment from Nx Cloud that reports on the status of the CI run.

Nx Cloud report

The See all runs link goes to a page with the progress and results of tasks that were run in the CI pipeline.

Run details

For more information about how Nx can improve your CI pipeline, check out one of these detailed tutorials:

Learn More