Migrating from Turborepo to Nx
Jump to:
- Easy Automated Migration Example - Automated migration from
create-turbo
workspace usingnx init
Spoiler alert: The diff is tiny! Nx is a superset of Turborepo, so it can already do everything Turborepo can do without any extra configuration. (learn more about it in our free video course)
1.gitignore | 3 +++ # Ignore the Nx cache
2package.json | 1 + # Add the "nx" package
3package-lock.json |
4nx.json | # Equivalent to turbo.json
5
- Configuration Migration Guide - How to mentally map Turborepo configuration to Nx configuration
- Command Equivalents - How to mentally map Turborepo commands to Nx commands
Why Migrate to Nx?
1. Superior Performance through Smarter Computation Caching
Nx is significantly faster than Turborepo, with open-source benchmarks showing more then 7x better performance in large monorepos. This is publicly verifiable here: large-monorepo benchmark.
The performance difference is particularly noticeable in larger, real-world monorepos, such as the one used in the benchmark.
This isn't just about raw speed - Nx's approach to file restoration means it's both faster and more reliable, especially when working with tools that watch files.
2. Fast CI
Just like Turborepo, Nx provides FREE remote caching to small teams, both self-hosted and via its own cloud (Vercel in the case of Turborepo, Nx Cloud in the case of Nx). And just like Turborepo, Nx provides paid plans for larger, more sophisticated teams that need a higher level of service. For self-hosted remote caching, small teams can apply for FREE Nx Powerpack License here: https://nx.dev/powerpack
However, unlike Turborepo, Nx's CI solution (Nx Cloud) goes way beyond just locating a shared cache on a server somewhere.
Nx Cloud allows you to ship updates to your users faster and with more confidence than ever before thanks to:
- Intelligently distributing your tasks across multiple machines without any manual "binning" configuration. Nx knows your workspace so let it decide what should run in what order.
- File artifacts automatically collected and distributed
- Built in support for versioning, changelog generation and publishing via Nx Release
- Finally solving the pain of long-running, flaky e2e tests by:
- Automatically splitting up a single e2e test task into multiple tasks that can run in parallel across multiple machines thanks to Atomizer
- Automatically detects and rerun flaky tasks
This is crucial for scaling large monorepos, as distributed task execution has a significantly higher impact on scalability than computation caching alone. You can scale without caching, but you cannot scale without distribution.
3. Supports you all the way from vanilla package manager workspaces through to advanced Enterprise Monorepos
Nx works effortlessly with zero plugins with industry standard package manager workspaces from npm
, yarn
, pnpm
and bun
. Turborepo also works with these, but that's where it starts and ends.
Nx additionally works with any programming language, framework and tooling. The core of Nx is written in Rust for speed and TypeScript for extensibility, with a first-class plugin API for both task execution and project/dependency graph analysis.
This means that you do not need to add package.json
files for languages like Rust, Java, Go, .NET, etc. that do not require them, and instead can install their respective Nx plugins.
Turborepo forces you to manually annotated your non-JavaScript packages, Nx understands it all through its first-class plugins, making it suitable for everything from open-source JavaScript tools with a handful of npm
packages through to the largest enterprise-grade polyglot/multi-languages monorepos.
4. Superior Developer Experience
Rich Visualization
Being able to visually explore your workspace is crucial for large monorepos:
- Nx: Rich, interactive visualizer, both locally via the
nx graph
CLI and for every pull request via Nx Cloud. (More in the docs) - Turborepo: Basic graphviz image export
IDE/Developer Tools
- Nx: provides powerful VSCode and WebStorm/IntelliJ extensions with nearly 2 million installations. Run tasks, code generators, the graph visualizer, interact with Nx Cloud CI runs and more.
- Turborepo: provides basic LSP support
5. Plugin System and Organizational Scaling
Nx is like the VSCode of build tools. Just as VSCode provides a core experience that can be enhanced with extensions for Git, Docker, MongoDB etc., Nx offers:
- Core functionality that works out of the box
- Rich plugin ecosystem for enhanced capabilities
- Community plugins for additional tools and frameworks
- Custom plugin development for organization-specific needs
This plugin system helps teams scale organizationally by:
- Enabling consistent task execution across all projects
- Automating large-scale refactorings
- Providing tools to analyze cache misses
- Supporting visibility constraints
6. Enterprise-Ready Features
- Conformance rules for consistently enforcing best practices across your organization
- On-premise and single-tenant Nx Cloud options
- Distributed task execution (similar to Google's Bazel)
- Advanced GitHub integration
- Comprehensive analytics and insights
- Module boundary rules essential for multi-team monorepos
7. Thriving Community
Nx has been battle-tested since 2016:
- ~5 million downloads per week
- Nearly 2 million unique Nx Console installations
- Rich ecosystem of third-party plugins, many with millions of downloads in their own right
- Used by over half of Fortune 500 companies in production
8. Incremental Adoption
Nx can be added to a repo with almost no friction. You can incrementally enable plugins and supporting features that are not available with Turborepo.
Here are some examples:
- Article: A New Nx Experience for TypeScript Monorepos and Beyond
- Video: Automatically Keep Your Codebase Updated
- Video: From PNPM Monorepo to Fast CI
- Video: AI-powered Debugging with Nx Cloud
Easy Automated Migration Example
The simplest way to understand the concepts is to see a basic migration example.
- Let's create a new Turborepo workspace using the recommended
create-turbo
command:
โฏ
npx create-turbo@latest
- Once that is finished, literally all we need to do make it a valid Nx workspace is run
nx init
:
โฏ
npx nx@latest init
That's it! As you can see, the diff is tiny:
1.gitignore | 3 +++ # Ignore the Nx cache
2package.json | 1 + # Add the "nx" package
3package-lock.json |
4nx.json | # Equivalent to turbo.json
5
- An
nx.json
file that is equivalent to theturbo.json
file was added - The
package.json
file was updated to add thenx
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.
Example: Basic Configuration Comparison
To help with understanding the new nx.json
file, let's compare it to the turbo.json
file:
1{
2 "$schema": "https://turbo.build/schema.json",
3 // Nx will automatically use an appropriate terminal output style for the tasks you run
4 "ui": "tui",
5 "tasks": {
6 "build": {
7 // This syntax of build depending on the build of its dependencies using ^ is the same
8 // in Nx
9 "dependsOn": ["^build"],
10 // 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
11 "inputs": ["$TURBO_DEFAULT$", ".env*"],
12 "outputs": [".next/**", "!.next/cache/**"]
13 },
14 "lint": {
15 // 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.
16 "dependsOn": ["^lint"]
17 },
18 "check-types": {
19 "dependsOn": ["^check-types"]
20 },
21 "dev": {
22 "cache": false,
23 // Nx has a powerful "continuous" setting for tasks in beta which even works across
24 // multiple machines. This is going to be generally available in Nx 21 and it will be a
25 // superset of Turborepo's "persistent" setting.
26 "persistent": true
27 }
28 }
29}
30
After running nx init
, you'll automatically have an equivalent nx.json
:
1{
2 "$schema": "./node_modules/nx/schemas/nx-schema.json",
3 "targetDefaults": {
4 "build": {
5 "dependsOn": ["^build"],
6 "inputs": ["{projectRoot}/**/*", "{projectRoot}/.env*"],
7 "outputs": ["{projectRoot}/.next/**", "!{projectRoot}/.next/cache/**"],
8 "cache": true
9 },
10 "lint": {
11 "dependsOn": ["^lint"],
12 "cache": true
13 },
14 "check-types": {
15 "dependsOn": ["^check-types"],
16 "cache": true
17 },
18 "dev": {
19 "cache": false
20 }
21 }
22}
23
Configuration Migration Guide
Most settings in the old turbo.json
file can be converted directly into nx.json
equivalents. Here's how to map each configuration property:
Global Configuration
Turborepo Property | Nx Equivalent |
---|---|
cacheDir | Set in cacheDirectory |
daemon | Use NX_DAEMON=false or set useDaemonProcess: false in nx.json |
envMode | Nx core does not block any environment variables. See React and Angular guides |
globalDependencies | Add to the sharedGlobals namedInput |
globalEnv | Add to the sharedGlobals namedInput as an env input |
globalPassThroughEnv | N/A. See Defining Environment Variables |
remoteCache | See Nx Replay |
ui | Nx will intelligently pick the most appropriate terminal output style, but it can be overridden with --output-style |
Task Configuration
Turborepo Property | Nx Equivalent |
---|---|
extends | N/A. Projects always extend targetDefaults from nx.json |
dependsOn | Same syntax |
env | Define env inputs |
passThroughEnv | N/A. See Defining Environment Variables |
outputs | Similar syntax |
cache | Similar syntax |
inputs | Similar syntax |
outputLogs | Use --output-style |
persistent | Nx has a powerful "continuous" setting for tasks in beta which even works across multiple machines. This is going to be generally available in Nx 21 and it will be a superset of Turborepo's "persistent" setting. |
interactive | All "continuous" tasks (coming in Nx 21) are intelligently and automatically interactive. |
Command Equivalents
Here's how Turborepo commands map to Nx:
Turborepo Command | Nx Equivalent |
---|---|
turbo run test lint build | nx run-many -t test lint build |
--cache-dir | Set in nx.json under cacheDirectory |
--concurrency | --parallel |
--continue | Use --nx-bail with the inverse value |
--cpuprofile | Use NX_PROFILE=profile.json |
--cwd | Available in run-commands executor |
--daemon | Use NX_DAEMON=false or set useDaemonProcess: false |
--dry-run | N/A. Nx has --dry-run for nx generate but not for running tasks |
--env-mode | See React and Angular guides |
--filter | Use lots of advanced project matcher syntax like -p admin-* or -p tag:api-* |
--force | nx reset and then run the command again |
--framework-inference | N/A. Nx plugins infer tasks automatically as a first class feature |
--global-deps | Use inputs in nx.json |
--graph | Similar syntax or nx graph for full interactive experience |
--heap | N/A. Use --verbose |
--ignore | Use .nxignore or .gitignore |
--log-order | Use --output-style |
--no-cache | Use --skip-nx-cache |
--output-logs | Use --output-style |
--only | N/A |
--parallel | N/A |
--preflight | N/A |
--summarize | N/A |
--token | Set Nx Cloud CI Access Token |
--team | See --token for Nx Cloud workspace selection |
--trace | N/A. Use --verbose |
--verbosity | Use --verbose |
turbo gen | Use nx generate |
turbo login | nx login - Create an Nx Cloud account |
turbo link | nx connect - Connect a workspace to an Nx Cloud account |
For a complete list of Nx commands and options, see the Nx CLI documentation.