Migrate from Turborepo to Nx
If you have an existing monorepo that uses Turborepo, switching to use Nx is a straight-forward process. After switching, you'll have cleaner CLI output, a better graph view and IDE support with the option to incorporate Nx plugins and take advantage of the features of an integrated repository. All this without increasing the complexity of your configuration files.
For more details, read our comparison of Nx and Turborepo
Initialize Nx
To switch to Nx, run this command:
โฏ
npx nx@latest init
See the Adding Nx to NPM/Yarn/PNPM Workspace guide for details about everything the nx init command does.
Convert turbo.json into Nx Configuration
Most of the settings in your turbo.json file can be converted directly into nx.json equivalents. The key configuration properties of dependsOn, inputs and outputs have a very similar syntax and can probably be copied over directly from the turbo.json pipeline into the nx.json targetDefaults.
If you have project-specific tasks defined in the root turbo.json (i.e. myreactapp#build) or in project-level turbo.json files (i.e. /packages/myreactapp/turbo.json), those settings should go in the nx property of the project's package.json (i.e. /packages/myreactapp/package.json).
Specific configuration property conversions are documented below.
Example
Let's say you start with the following turbo.json file:
1{
2  "$schema": "https://turbo.build/schema.json",
3  "pipeline": {
4    "build": {
5      "dependsOn": ["^build"],
6      "outputs": ["dist/**"]
7    },
8    "docs#build": {
9      "dependsOn": ["^build"],
10      "outputs": ["www/**"]
11    },
12    "test": {
13      "dependsOn": ["build"],
14      "outputs": []
15    },
16    "e2e": {
17      "dependsOn": ["build"],
18      "outputs": []
19    }
20  },
21  "globalDependencies": ["babel.config.json"]
22}
23Creating the equivalent configuration with Nx yields the following files:
1{
2  "$schema": "./node_modules/nx/schemas/nx-schema.json",
3  "namedInputs": {
4    "sharedGlobals": ["babel.config.json"],
5    "default": ["{projectRoot}/**/*", "sharedGlobals"]
6  },
7  "targetDefaults": {
8    "build": {
9      "dependsOn": ["^build"],
10      "inputs": ["default"],
11      "outputs": ["{projectRoot}/dist"],
12      "cache": true
13    },
14    "test": {
15      "dependsOn": ["build"],
16      "inputs": ["default"],
17      "cache": true
18    },
19    "e2e": {
20      "dependsOn": ["build"],
21      "inputs": ["default"],
22      "cache": true
23    }
24  },
25  "nxCloudAccessToken": "..."
26}
271{
2  "name": "docs",
3  // etc...
4  "nx": {
5    "targets": {
6      "build": {
7        "outputs": ["www/**"]
8      }
9    }
10  }
11}
12Specific Configuration Property Conversions
For each turbo.json configuration property, the equivalent Nx property is listed.
| Global Configuration: | |
|---|---|
| globalDependencies | add to the sharedGlobalsnamedInput | 
| globalEnv | add to the sharedGlobalsnamedInputas anenvinput | 
| globalPassThroughEnv | N/A. See Defining Environment Variables | 
| globalDotEnv | add to the sharedGlobalsnamedInput | 
| Task Configuration: | |
|---|---|
| extends | N/A. The project configurations will always extend the targetDefaultsdefined innx.json. | 
| pipeline[task].dependsOn | Same syntax. | 
| pipeline[task].dotEnv | Define file inputs | 
| pipeline[task].env | Define env inputs | 
| pipeline[task].passThroughEnv | N/A. See Defining Environment Variables | 
| pipeline[task].outputs | Same syntax. | 
| pipeline[task].cache | Same syntax | 
| pipeline[task].inputs | Same syntax. | 
| pipeline[task].outputMode | Use the --output-stylecommand line flag | 
| pipeline[task].persistent | N/A. | 
Command Equivalents
| turbo run test lint build | nx run-many -t test lint build | 
| --cache-dir | Set in nx.jsonundercacheDirectory | 
| --concurrency | --parallel | 
| --continue | Use --nx-bailwith the inverse value | 
| --cwd | Available when using the run-commandsexecutor | 
| --dry-run | N/A. Nx has --dry-runfornx generatebut not for running tasks. | 
| --env-mode | N/A | 
| --filter | Use -p admin-*or-p tag:api-*. Also seenx affected. | 
| --graph | Same syntax or nx graphfor the entire graph | 
| --force | nx resetand then run the command again | 
| --global-deps | Use inputsin thenx.jsonor project configuration | 
| --framework-inference | Nx knows if you're using a particular framework if you use an executor for that framework. | 
| --ignore | Use an .nxignorefile (or.gitignore) | 
| --log-order | Use --output-style | 
| --no-cache | Use --skip-nx-cache | 
| --no-daemon | Use NX_DAEMON=falseor setuseDaemonProcess: falseinnx.json | 
| --output-logs | Use --output-style | 
| --only | N/A | 
| --parallel | N/A | 
| --remote-only | N/A. Can ignore the remote cache with --no-cloud. | 
| --summarize | N/A | 
| --token | Set the Nx Cloud token in nx.jsonor as an environment variable (NX_CLOUD_ACCESS_TOKEN) | 
| --team | See --tokenfor choosing a different Nx Cloud workspace. You can use--runnerto choose a different runner defined in thenx.jsonfile. | 
| --preflight | N/A | 
| --trace | N/A. --verbosefor more logging. | 
| --heap | N/A. --verbosefor more logging. | 
| --cpuprofile | Use NX_PROFILE=profile.json. | 
| --verbosity | Use --verbose | 
| turbo gen | Use nx generate | 
| turbo login | No need. Create an Nx Cloud account once to set up Nx Cloud. | 
| turbo link | Create an Nx Cloud account |