Configure TypeScript Project References in an Nx Workspace

In Nx 20, the @nx/js plugin provides the ability to incrementally build projects in a monorepo using TypeScript Project References. Nx also provides a ts preset for create-nx-workspace that configures project references and uses workspaces to link projects instead of TypeScript compilerOptions Paths.

The TypeScript team recommends using project references when working in a monorepo, but until now the configuration settings were difficult to maintain. Each project is required to list its own project dependencies in the references property of the tsconfig.json file so that TypeScript can incrementally compile projects in the correct order. In a large monorepo, maintaining those settings manually is cost prohibitive. To solve this problem, the @nx/js plugin registers a sync generator to automatically update the references based on Nx's project graph before any TypeScript build task is executed.

Create a New Nx Workspace Using Project References

We anticipate that this style of compiling projects will eventually become the default, but currently it will only be enabled for repositories configured in a specific way. Existing workspaces will continue to function as usual and there is no migration path yet. You can generate a new repository with these settings by using the --preset=ts flag of the create-nx-workspace command.

npx create-nx-workspace --preset=ts

Empty Workspace with Paths

To generate an empty Nx workspace that links projects with the compilerOptions.paths property and does not use project references, use create-nx-workspace --preset=apps

This will generate an empty repository that is configured to use TypeScript project references. To see the new functionality in action, create some TypeScript projects and make sure to use the tsc bundler option.

nx g @nx/js:lib packages/cart --bundler=tsc

nx g @nx/js:lib packages/utils --bundler=tsc

These generators will detect that your repository is configured to use project references and update the configuration accordingly. If these generators were executed in an Nx repository that used compilerOptions.paths, they would update that setting instead.

To make cart depend on utils, update packages/cart/package.json like this:

packages/cart/package.json
1{ 2 "dependencies": { 3 "utils": "*" 4 } 5} 6

Now if you run nx build cart or directly run nx sync, the packages/cart/tsconfig.json file will have its references updated for you.

Project Reference Configuration Files

Nx expects the following configuration settings to be in place in order to use TypeScript project references to build projects. Most of this configuration is set up and maintained for you automatically by Nx.

Identify projects in the workspaces property in the root package.json file.

package.json
1{ 2 "workspaces": ["packages/*"] 3} 4

The root tsconfig.base.json should contain a compilerOptions property and no other properties. compilerOptions.composite and compilerOptions.declaration should be set to true. compilerOptions.paths should not be set.

tsconfig.base.json
1{ 2 "compilerOptions": { 3 // Required compiler options 4 "composite": true, 5 "declaration": true 6 // Other options... 7 } 8} 9

The root tsconfig.json file should extend tsconfig.base.json and not include any files. It needs to have references for every project in the repository so that editor tooling works correctly.

tsconfig.json
1{ 2 "extends": "./tsconfig.base.json", 3 "files": [], // intentionally empty 4 "references": [ 5 // UPDATED BY PROJECT GENERATORS 6 // All projects in the repository 7 ] 8} 9

Each project's tsconfig.json file should extend the tsconfig.base.json file and list references to the project's dependencies.

packages/cart/tsconfig.json
1{ 2 "extends": "../../tsconfig.base.json", 3 "files": [], // intentionally empty 4 "references": [ 5 // UPDATED BY NX SYNC 6 // All project dependencies 7 { 8 "path": "../utils" 9 }, 10 // This project's other tsconfig.*.json files 11 { 12 "path": "./tsconfig.lib.json" 13 }, 14 { 15 "path": "./tsconfig.spec.json" 16 } 17 ] 18} 19

Each project's tsconfig.lib.json file extends the project's tsconfig.json file and adds references to the tsconfig.lib.json files of project dependencies.

packages/cart/tsconfig.lib.json
1{ 2 "extends": "./tsconfig.json", 3 "compilerOptions": { 4 // Any overrides 5 }, 6 "include": ["src/**/*.ts"], 7 "exclude": [ 8 // exclude config and test files 9 ], 10 "references": [ 11 // UPDATED BY NX SYNC 12 // tsconfig.lib.json files for project dependencies 13 { 14 "path": "../utils/tsconfig.lib.json" 15 } 16 ] 17} 18

The project's tsconfig.spec.json does not need to reference project dependencies.

packages/cart/tsconfig.spec.json
1{ 2 "extends": "./tsconfig.json", 3 "compilerOptions": { 4 // Any overrides 5 }, 6 "include": [ 7 // test files 8 ], 9 "references": [ 10 // tsconfig.lib.json for this project 11 { 12 "path": "./tsconfig.lib.json" 13 } 14 ] 15} 16