Set Up Nx
Creating an Nx Workspace
If you are fortunate enough to start a new project from scratch, then you can simply generate a new Nx workspace using the following command:
- bun
- pnpm
- npm
- yarn
bun create nx-workspace@latest <name> --preset <preset>
pnpm create nx-workspace@latest <name> --preset <preset>
npm create nx-workspace@latest <name> --preset <preset>
yarn create nx-workspace@latest <name> --preset <preset>
where preset
is one of the following depending on your needs:
apps
: creates an empty workspace.ts
: creates an empty workspace with TypeScript support.angular|expo|express|nest|next|nuxt|react|react-native|vue
: creates a workspace with a single application using the framework of your choice.
There is also the npm
preset but we only recommend it if you really know what you are doing.
Tell me more
The npm
preset creates an empty workspace with two main differences (in order to align with the behavior of Lerna):
- the package manager is configured to install the dependencies described in each project's
package.json
(Cf. PNPM Workspaces, NPM Workspaces, Yarn Workspaces) which means that Single Version Policy will not be enforced. analyzeSourceFiles
option is set tofalse
which means that Nx will not analyze the dependency graph between projects. This also means that Nx will not warn us if we forgot a dependency in a project'spackage.json
(Cf. Dependency Checks Rule).
Note that these two behaviors can be controlled separately.
Curious about NPM workspaces along with Nx?
Check out Analog & RxJS repositories.
Note that analyzeSourceFiles
is set to true
in both repositories.
The exhaustive list of built-in presets is available here: https://nx.dev/nx-api/nx/documents/create-nx-workspace#preset.
Install Nx Globally
While this is optional, it is helpful to install Nx globally:
- bun
- pnpm
- npm
- yarn
bun add -g nx@latest
pnpm add -g nx@latest
npm install -g nx@latest
yarn global add nx@latest
Note that the global nx
command will always use the workspace's version of Nx.
You don't have to worry about version mismatch.
Standalone vs. Integrated
With most presets, you will be asked to choose between a Standalone or an Integrated Monorepo workspace.
> Integrated monorepo, or standalone project? …
Integrated Monorepo: Nx creates a monorepo that contains multiple projects.
Standalone: Nx creates a single project and makes it fast.
Standalone mode will create an application at the root of the workspace. The file structure would look something like this:
├── README.md
├── index.html
├── nx.json
├── package.json
├── project.json
├── src
│ ├── app
│ │ ├── app.spec.ts
│ │ └── app.ts
│ └── main.ts
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.spec.json
└── vite.config.ts
It will also add scripts like build
, start
, and test
to the package.json
file.
Integrated Monorepo mode will create the application in the apps
directory and create a tsconfig.base.json
that all projects will extend from. The file structure would look something like this:
├── README.md
├── apps 👈
│ └── marmicode 👈
│ ├── index.html
│ ├── project.json
│ ├── src
│ │ ├── app
│ │ │ ├── app.spec.ts
│ │ │ ├── app.ts
│ │ └── main.ts
│ ├── tsconfig.app.json
│ ├── tsconfig.json
│ ├── tsconfig.spec.json
│ └── vite.config.ts
├── nx.json
├── package.json
└── tsconfig.base.json 👈
Note that you can always switch from Standalone to Integrated Monorepo later on using the @nx/workspace:convert-to-monorepo
generator:
nx g convert-to-monorepo
or by moving the application to the apps
directory using the @nx/workspace:move
generator:
nx g move --projectName <name> --destination apps/<name>
Make sure to add the @nx/workspace
plugin:
nx add @nx/workspace
Prefer Integrated Monorepo mode over Standalone.
In our experience, Standalone workspaces eventually end up being migrated to Integrated Monorepo.
In addition to this, note that even though it is possible to move the application using @nx/workspace:move
generator later on, the process is not magic and might miss some things like files added after the initial creation. (e.g. docs, test setup files, etc...)
Migrating to Nx
If you are migrating an existing project to Nx, you have two options:
- Add Nx to an existing workspace.
- 🍰 Simple.
- 🪜 More progressive.
- 🫤 Not symmetric to starting from scratch.
- Create a new Nx workspace and move existing code into it.
- 👯 Symmetric to starting from scratch.
- 💪 Get all the advantages of using Nx from day 1.
- 😓 Less progressive and might require a bit more work than just running a command.
If you don't have a complex setup, we recommend the second option. In fact, the second option will provide a better starting point. (e.g. nx init
will not set up a linter for you, but creating a new workspace will.)
Option 1: Add Nx to an Existing Workspace
Given an existing repository, we can add Nx to it using the following command:
nx init --integrated
Note that the --integrated
option will only work on Angular CLI workspaces and Create React App (CRA) projects.
While this command works pretty well in most common cases, it is not perfect because:
- it will generally reuse existing npm scripts (e.g.
build
,start
,test
, etc...) which might not be optimal compared to what Nx executors can offer, - it will prompt you to choose which of these scripts are cacheable and what are their outputs, but it will not ask about their inputs which we would have to configure later on in the
nx.json
file, - the final result will not be exactly aligned with an Nx workspace created from scratch.
Option 2: Merge a new Nx workspace into an existing repository
If you are migrating an existing repository to Nx, you can create a new Nx workspace and merge it into the existing repository.
This approach gives you more control while keeping you aligned with Nx defaults just as if you were starting a new project from scratch.
Step 1 - Create a new Nx workspace
- bun
- pnpm
- npm
- yarn
bun create nx-workspace@latest <name> --preset <preset>
pnpm create nx-workspace@latest <name> --preset <preset>
npm create nx-workspace@latest <name> --preset <preset>
yarn create nx-workspace@latest <name> --preset <preset>
Step 2 - Merge the new Nx workspace into the existing repository
Go to your existing repository and merge the new Nx workspace into it:
# Add the new Nx workspace as a remote.
git remote add nx-workspace <path|url>
# Merge the new Nx workspace into the existing repository.
git fetch nx-workspace
git merge nx-workspace/main --allow-unrelated-histories
The trick here resides in the --allow-unrelated-histories
option which will allow you to merge two unrelated repositories.
Step 3 - Fix conflicts
You will most likely have conflicts to resolve. We recommend doing this using mob programming with your team.
We also recommend keeping Nx defaults as much as possible and only changing what is really necessary. The less you change, the less you diverge, and the easier it will be to upgrade Nx in the future.
Step 4 - Move app's source code into dedicated directory
If your existing repository has an app at the root, we recommend moving its source code into the apps/<name>
directory created when generating the Nx workspace.
This makes it clear whether a file (configuration, documentation etc...) is specific to the app or to the whole workspace. It will also make things easier in the long run (e.g. configuring caching, adding apps/libs).
Using Nx
You can now run the Nx task of your choice to build, test or serve your applications.
List the projects in your workspace using the following command:
nx show projects
List the available targets for a specific project using the following command:
nx show project <project-name> --web
Learn more about Nx tasks in the Nx documentation.