I know it's hard to believe but Nx 20 is here! There's a lot of great updates in this release, but look back at some of the major features from Nx 19:
- Added
nx import
to import existing external projects, more on that below. - Added a generator to convert all your Nx Plugins to use inferred tasks.
- Moved to rspack as the default bundler for Module Federation
- Added file-based versioning for Nx Release
- Created a new plugin for Gradle and support for task atomization
With Nx 20 we're keeping the momentum going and bringing some quality improvements to the overall monorepo experience as well as a boost in speed for TypeScript projects.
@nx
All The Things!
If you've been around the Nx ecosystem for any amount of time, you're probably aware that our plugins were published originally under the @nrwl
npm scope. Since version 16, we've provided backwards compatibility by reexporting @nx
scoped packages from @nrwl
. With Nx 20 though, we'll be officially dropping support for the @nrwl
scoped packages and they will no longer be published to npm. For projects that still have the older packages in them, our migration docs can guide you to what the new packages are in order for you to update any impacted dependencies.
TypeScript Project References For Monorepos
Project References allows TypeScript to process individual projects rather than the entire monorepo as a whole. This is a huge improvement in terms of build times and developer experience. However, Project References comes with a maintenance cost, as it is up to you to update these references. In a large monorepo, this cost is prohibitive.
With Nx 20, when using create-nx-workspace --preset=ts
, workspaces will use Project References out of the box. Nx removes the maintenance cost of this feature by automatically updating the references for you when you run build
or typecheck
targets. You can also run nx sync
to update project references in your tsconfig.json
, and nx sync:check
in CI to validate the workspace.
In addition to adopting Project References, we're also changing the way we link projects in a TypeScript monorepos. Workspaces is the standard way to link packages in monorepos. This is a feature that all modern package managers support, such as npm, yarn, pnpm, and bun, where you can declare a workspace
key in your package.json
and provide it an array of paths. Then on install, your package manager will traverse any directories that it finds in the workspaces key, and link them to your node-modules
. This built in feature provides a much more standard way of connecting your packages in a monorepo that it’s a no-brainer. Now we have a proper way to provide type information and have your packages available in a way developers are used to.
Note that we've enabled Project References and Workspaces for the TS preset (i.e. --preset=ts
), and we're working on extending this support for all other presets soon (Angular, React, Vue, Node). If you are an existing Nx user and want to create an empty workspace in the previous "integrated" style, you can use create-nx-workspace --preset=apps
.
@nx/rspack
Graduates From Labs 🎓
Rspack has become one of the most exciting new bundlers in recent years. With a webpack-compatible API, it's a painless migration for folks who want faster builds without having to rewrite their entire build process. At Nx, we're big fans of Rspack and have been working on a plugin for folks who would like to migrate. With that in mind, the @nx/rspack
plugin has officially been merged into the main Nx repository and will become a fully supported plugin for the ecosystem. Want to learn more about Rspac in general? Check out our recent live stream where we deep dive into how to use Rspack and cover it’s involvement with module federation.
In addition to this, Nx core team member Colum Ferry has taken the work he's done on the Rspack plugin and brought it to the Angular ecosystem! He's recently released @ng-rspack/nx
to bring Rspack support to your Angular projects. Simply install the plugin and generate a new app in your workspace to try it out!
❯
# In an Nx Workspace (npx create-nx-workspace)
❯
# Install Package
❯
npm install @ng-rspack/nx
❯
# Run the app generator
❯
npx nx g @ng-rspack/nx:app apps/myapp
❯
# Serve the app
❯
npx nx serve myapp
❯
# Build the app
❯
npx nx build myapp
❯
# Run the e2es
❯
npx nx e2e myapp-e2e
ESLint v9 Updates
In Nx 19.8, we highlighted that workspaces will now be created with eslint
v9, and typescript-eslint
v8.
This not only brings us inline with the latest version of eslint and typescript-eslint, but also that flat config is only supported moving forward. Nx users should migrate to this new config format using our flat config generator.
For more on eslint's flat config, and how to use our generator to get to flat config checkout this video:
Nx Release: More Powerful And Flexible Versioning
nx release
has added many powerful versioning capabilities since it was first made public as part of Nx 19. We are super excited about an in progress ground-up reworking of our versioning logic that powers nx release
and the programmatic API releaseVersion()
that will continue to support all these features, and allow for even more complex and large scale workspaces to be supported.
For example, release groups have existed as a concept from the very beginning, but their effectiveness is currently not maximized because it is not supported to have project dependencies that span across release group boundaries. The new version coming in a later Nx v20 minor release makes it possible for any number of dependency relationships to exist across any number of release group boundaries.
Additionally, for workspaces that contain multiple different programming languages, extending the versioning logic within nx release
can currently be quite verbose, with maintenance being quite a burden due to the business logic that lives within the version generator abstraction, and this is what gets implemented per language/ecosystem.
The Nx Team provides the JavaScript version generator out of the box, so for many users, this is not a concern. But for those working with Go, Rust, Dotnet, Java etc, currently a lot of logic needs to be reimplemented and kept up to date with the latest features. In the upcoming versioning rework, the abstraction required for each new language/ecosystem is tiny and purely deals with interacting with the relevant manifest file and registry, if applicable. All feature capabilities are maintained on the Nx core side. Once this new versioning implementation is available in an Nx v20 minor release we will update our documentation to provide guidance on how to opt in, before it ultimately becomes the primary implementation in Nx v21.
Importing Existing Projects
Another important feature worth highlighting with Nx 20 is the ability to import external projects and add them to your Nx workspace with nx import
. Not only does nx import
ease the process of consolidating separate projects into one monorepo, it also maintains that original projects git history. Now you have the full historical context of that particular project. In addition to just being able to bring in external projects, nx import
will also analyze the project and provide recommended Nx plugins to be added to your workspace. So if you're importing a Vite project that also has ESLint, nx import
will detect the config files and suggest installing them into your workspace. So not only is migrating to a monorepo simpler, you can keep your existing tool chain and keep working with a setup you are familiar with. Get a glance of how import works in a past live stream and be on the lookout for more on import in the future.
Caching - Now With Databases
Caching is a big feature of Nx and is one of many reasons why we can have such a fast build time. But our approach to caching has historically been lacking for a bit. Prior to Nx 20, we utilized a file-based caching system where the build results were written to disk and were read from disk when any subsequent builds were performed. This solution could lead to some performance issues if the cached output was rather large, leading to the build process needing to wait for any output to be loaded from the cache. In Nx 20, we've adopted a database-driven solution for caching your results. Not only is this a faster mechanism for caching, but it's a much more robust solution than simply reading/writing from a directory. We can make sure that as your monorepo scales, the caching portion does not become a bottleneck. While the new database caching solution is the default for Nx 20, you can opt-out by setting useLegacyCache
in your nx.json
1{
2 "useLegacyCache": true,
3 "namedInputs": {...}
4}
5
So Long Derived Directories 👋
Generating apps and libraries in a monorepo is something folks do quite regularly and part of that is telling Nx where it should put things. So you've probably seen this prompt before:
This is where the concept of derived directories comes in. It will try to inspect your project and put things where it makes sense. But with Nx 20, we're moving away from using derived directories for generators. Now, you'll need to provide the directory
where you want your apps or libraries to be generated to.
Wrapping Up
Updating Nx and its plugins is easy as we ship an automated migration command.
❯
npx nx migrate latest
❯
npx nx migrate --run-migrations
There's a lot more in Nx 20, so be sure to check the full changelog for all the details on everything in this major release and any of our past releases.