Skip to content

Nx is a superset of Turborepo, so migrating requires minimal effort. The diff is tiny: an nx.json file (equivalent to turbo.json), the nx package added to package.json, and a .gitignore entry for the Nx cache. No changes to your existing projects or scripts are needed.

  1. Let's create a new Turborepo workspace using the recommended create-turbo command:
Terminal window
npx create-turbo@latest
  1. Once that is finished, literally all we need to do make it a valid Nx workspace is run nx init:
Terminal window
npx nx@latest init

That's it! As you can see, the diff is tiny:

.gitignore | 3 +++ # Ignore the Nx cache
package.json | 1 + # Add the "nx" package
package-lock.json |
nx.json | # Equivalent to turbo.json
  • An nx.json file that is equivalent to the turbo.json file was added
  • The package.json file was updated to add the nx dev dependency (and the package-lock.json was updated accordingly)
  • The .gitignore entry for the Nx cache was added automatically

It's important to remember that Nx is a superset of Turborepo, it can do everything Turborepo can do and much more, so there is absolutely no special configuration needed for Nx, it just works on the Turborepo workspace.

To help with understanding the new nx.json file, let's compare it to the turbo.json file:

{
"$schema": "https://turbo.build/schema.json",
// Nx will automatically use an appropriate terminal output style for the tasks you run
"ui": "tui",
"tasks": {
"build": {
// This syntax of build depending on the build of its dependencies using ^ is the same
// in Nx
"dependsOn": ["^build"],
// Inputs and outputs are in Turborepo are relative to a particular package, whereas in Nx they are consistently from the workspace root and it therefore has {projectRoot} and {projectName} helpers
"inputs": ["$TURBO_DEFAULT$", ".env*"],
"outputs": [".next/**", "!.next/cache/**"]
},
"lint": {
// Turborepo tasks are assumed to be cacheable by default, so there is no recognizable configuration here. In Nx, the "cache" value is clearly set to true.
"dependsOn": ["^lint"]
},
"check-types": {
"dependsOn": ["^check-types"]
},
"dev": {
// Nx uses "continuous" instead of "persistent"
"persistent": true
}
}
}

After running nx init, you'll automatically have an equivalent nx.json:

{
"$schema": "./node_modules/nx/schemas/nx-schema.json",
"targetDefaults": {
"build": {
"dependsOn": ["^build"],
"inputs": ["{projectRoot}/**/*", "{projectRoot}/.env*"],
"outputs": ["{projectRoot}/.next/**", "!{projectRoot}/.next/cache/**"],
"cache": true
},
"lint": {
"dependsOn": ["^lint"],
"cache": true
},
"check-types": {
"dependsOn": ["^check-types"],
"cache": true
},
"dev": {
"continuous": true
}
}
}

Most settings in the old turbo.json file can be converted directly into nx.json equivalents. Here's how to map each configuration property:

Turborepo PropertyNx Equivalent
cacheDirSet in cacheDirectory
daemonUse NX_DAEMON=false or set useDaemonProcess: false in nx.json
envModeNx core does not block any environment variables. See React and Angular guides
globalDependenciesAdd to the sharedGlobals namedInput
globalEnvAdd to the sharedGlobals namedInput as an env input
globalPassThroughEnvN/A. See Defining Environment Variables
remoteCacheSee Nx Replay
uiNx will intelligently pick the most appropriate terminal output style, but it can be overridden with --output-style
Turborepo PropertyNx Equivalent
extendsN/A. Projects always extend targetDefaults from nx.json
dependsOnSame syntax
envDefine env inputs
passThroughEnvN/A. See Defining Environment Variables
outputsSimilar syntax
cacheSimilar syntax
inputsSimilar syntax
outputLogsUse --output-style
persistentUse continuous
interactiveN/A. Tasks marked continuous can accept stdin automatically.

Here's how Turborepo commands map to Nx:

Turborepo CommandNx Equivalent
turbo run test lint buildnx run-many -t test lint build
turbo run build --affectednx affected -t build
turbo devtoolsnx graph for full interactive experience, also available in Nx Console
--cache-dirSet in nx.json under cacheDirectory
--concurrency--parallel
--continueUse --nx-bail with the inverse value
--cpuprofileUse NX_PROFILE=profile.json
--cwdAvailable in run-commands executor
--daemonUse NX_DAEMON=false or set useDaemonProcess: false
--dry-runUse nx show target <project>:<target> --inputs --outputs to preview inputs and outputs (available since 22.6.0+)
--env-modeSee React and Angular guides
--filterUse lots of advanced project matcher syntax like -p admin-* or -p tag:api-*
--forcenx reset and then run the command again
--framework-inferenceN/A. Nx plugins infer tasks automatically as a first class feature
--global-depsUse the sharedGlobals namedInput. Nx is far more flexible with composable namedInputs
--graphSimilar syntax or nx graph for full interactive experience
--heapN/A. Use --verbose
--ignoreUse .nxignore or .gitignore
--log-orderUse --output-style
--no-cacheUse --skip-nx-cache
--output-logsUse --output-style
--onlyN/A
--parallelN/A
--preflightN/A
--summarizeN/A
--tokenSet Nx Cloud CI Access Token
--teamSee --token for Nx Cloud workspace selection
--traceN/A. Use --verbose
--verbosityUse --verbose
turbo genUse nx generate
turbo loginnx login - Create an Nx Cloud account
turbo linknx connect - Connect a workspace to an Nx Cloud account

For a complete list of Nx commands and options, see the Nx CLI documentation.