VOOZH about

URL: https://blog.logrocket.com/boost-your-productivity-with-typescript-project-references/

⇱ Boost your productivity with TypeScript project references - LogRocket Blog


2021-04-19
865
#typescript
Paul Cowan
41283
πŸ‘ Image

See how LogRocket's Galileo AI surfaces the most severe issues for you

No signup required

Check it out

If you have a TypeScript codebase in a monorepo that is not using TypeScript project references then you are missing a trick.

πŸ‘ Boost your productivity with TypeScript project references

TypeScript project references have been around since TypeScript 3.0 and allow you to specify dependant packages in the tsconfig.json that the current package depends on. When you build a package with dependencies, then the dependencies get built first.

The tsconfig.json below specifies that this package references a common package and that the common package is built before the current package:

{
 "extends": "../tsconfig-base.json",
 "compilerOptions": {
 "outDir": "../lib/animals",
 "rootDir": ".",
 },
 "references": [
 { "path": "../core" }
 ]
}

Project references are specified via a references array of objects with a path property. The path property is a relative path to a different location containing a tsconfig.json file.

If the project were not using project references, then all packages would have to be built individually, which can be a huge drag if there are multiple dependent packages.

πŸš€ Sign up for The Replay newsletter

The Replay is a weekly newsletter for dev and engineering leaders.

Delivered once a week, it's your curated guide to the most important conversations around frontend dev, emerging AI tools, and the state of modern software.

Building incrementally

The -b or --build switch is added to the tsc compiler when transpiling a package that has project references:

 > tsc -b # Use the tsconfig.json in the current directory
 > tsc -b src # Use src/tsconfig.json
 > tsc -b foo/prd.tsconfig.json bar # Use foo/prd.tsconfig.json and bar/tsconfig.json

A successful build will output a tsconfig.tsbuildinfo, used in subsequent builds to ensure only new code or changed code is built for a faster build time. The tsconfig.tsbuildinfo file contains the signatures and timestamps of all files required to build the whole project. On subsequent builds, TypeScript will use that information to detect the least costly way to type check and emit changes to your project.

Watch all packages in the monorepo for changes

What has really boosted my TypeScript development is the ability to have tsc watch for changes in every package of a monorepo.

I have a script like this running the whole time I am developing:

"watch": "tsc -b ./tsconfig.packages.json --watch"

When the watch script is running, any TypeScript changes in the whole monorepo will result in a new efficient build:

πŸ‘ tsc watching for changes

Monorepo project structure

In most monorepos, the individual package nodes are in a folder named packages. Below is an example monorepo with the various tsconfig.json files strategically placed with surgical precision:

tsconfig.base.json # base tsconfig.json that all packages will extend
tsconfig.packages.json # tsconfig.json that is used to watch eveything
all packages
/package.json
/packages
 /common # Common utitliies used by all package
 /src
 .index.ts # entry point for package
 /tsconfig.json # Config file for 'common' project
 /package.json
 /web # Depends on 'common'
 /src
 .index.ts # entry point for package
 /tsconfig.json # Config file for 'web' project
 /api # Depends on 'common'
 /src
 .index.ts # entry point for package
 /tsconfig.json # Config file for 'api' project
 /package.json

At the root folder is a tsconfig.base.json file that is extended by all packages in the monorepo:

{
 "compilerOptions": {
 "baseUrl": ".",
 "composite": true,
 "declaration": true,
 "declarationMap": true,
 "paths": {
 "common": ["packages/common/src"],
 "web": ["packages/web/src"],
 "api": ["packages/api/src"]
 }
 }
}

There is actually a lot going on here:

  • "composite": true instructs tsc that there are project references
  • "declarationMap": true adds source maps for .d.ts declaration files. It means Go to Definition in VS code and will go to the actual file and not the .d.ts file
  • The paths field contains an object with each object key (common, web, or API in this example) pointing to a package’s location. With this set, we can import packages without a nasty relative or absolute path.
    e.g. import { a } from 'web';

In this example, each package extends tsconfig.base.json using the extends option of tsconfig:

{
 "extends": "../tsconfig-base.json",
 "compilerOptions": {
 "rootDir": ".",
 },
 "references": [
 { "path": "../core" }
 ]
}

Watching and building

The tsconfig.packages.json at the root of the project structure references all packages that we want to watch or build:

{
 "files": [],
 "references": [
 {
 "path": "./packages/common"
 },
 {
 "path": "./packages/web"
 },
 {
 "path": "./packages/api"
 }
 ]
}

With this structure in place, we can now build all packages in one swoop:

tsc -b ./tsconfig.packages.json

or watch:

tsc -b ./tsconfig.packages.json

Useful switches

The following switches are handy when working with project references:

--verbose: Prints out verbose logging to explain what is going on (may be combined with any other flag)
--dry: Shows what would be done but does not actually build anything
--clean: Deletes the outputs of the specified projects (may be combined with --dry)
--force: Acts as if all projects are out of date
--watch: Watch mode (may not be combined with any flag except --verbose)

Webpack

Bundlers like webpack and Rollup did not offer support for project references for quite some time, and Rollup only has partial support. This has not helped adoption.

webpack ts-loader

When configuring the webpack loader ts-loader, you need to set the projectReferences option to true:

{
 test: /\.tsx?$/,
 use: {
 loader: 'ts-loader',
 options: {
 projectReferences: true,
 },
 },
},

Epilogue

I do most of my main development in monorepo’s these days, both in client projects and my own personal development. If I use TypeScript as my main language, then I will enable project references just like I have outlined here. I find them a great productivity boost that not everyone is using.

LogRocket understands everything users do in your web and mobile apps.

πŸ‘ LogRocket Dashboard Free Trial Banner

LogRocket lets you replay user sessions, eliminating guesswork by showing exactly what users experienced. It captures console logs, errors, network requests, and pixel-perfect DOM recordings β€” compatible with all frameworks, and with plugins to log additional context from Redux, Vuex, and @ngrx/store.

With Galileo AI, you can instantly identify and explain user struggles with automated monitoring of your entire product experience.

Modernize how you understand your web and mobile apps β€” start monitoring for free.

πŸ‘ Image
πŸ‘ Image
πŸ‘ Image

Stop guessing about your digital experience with LogRocket

Get started for free

Recent posts:

What is TSRX?: What JSX would look like if it were designed today

TSRX adds first-class control flow, conditional hooks, and scoped styles to React via a TypeScript compiler extension β€” no new framework required.

πŸ‘ Image
Ikeh Akinyemi
Jun 12, 2026 β‹… 6 min read

How to add authentication to a React Native app with Better Auth

Learn how to build a full React Native auth system using Better Auth and Expo β€” with email/password login, Google OAuth, session persistence, and protected routes.

πŸ‘ Image
Chinwike Maduabuchi
Jun 9, 2026 β‹… 13 min read

AI dev tool power rankings & comparison [June 2026]

Compare the top AI development tools and models of June 2026. View updated rankings, feature breakdowns, and find the best fit for you.

πŸ‘ Image
Chizaram Ken
Jun 8, 2026 β‹… 11 min read

How to check username availability at scale with Bloom filters

Learn how Bloom filters reduce database lookups for username availability checks while preserving correctness at scale.

πŸ‘ Image
Rosario De Chiara
Jun 8, 2026 β‹… 6 min read
View all posts

Hey there, want to help make our blog better?

Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.

Sign up now