Skip to main content

Overview

Project references are a feature that allows you to structure your TypeScript programs into smaller pieces. This enables:
  • Faster builds through incremental compilation
  • Better code organization and separation of concerns
  • Enforced logical boundaries between components
  • Improved IDE performance
Project references are essential for large TypeScript projects and monorepos.

How Project References Work

Project references allow TypeScript to:
  1. Build projects independently and incrementally
  2. Cache build outputs in .tsbuildinfo files
  3. Enforce dependencies between projects
  4. Navigate and edit across multiple projects efficiently

Basic Setup

1. Enable Composite Mode

For a project to be referenced, it must have composite: true in its tsconfig.json:
tsconfig.json
When composite is enabled, TypeScript automatically enables declaration if not explicitly set.

2. Add References

In the consuming project, add references to the dependencies:
tsconfig.json

3. Build with References

Use the --build flag to build projects with references:
This command:
  • Finds all referenced projects
  • Detects if they’re up-to-date
  • Builds out-of-date projects in the correct order
  • Builds the current project

Real-World Example: TypeScript Compiler

The TypeScript compiler itself uses project references extensively. Here’s how it’s structured:

Root Configuration

From src/tsconfig.json:
src/tsconfig.json
Notice that the root tsconfig.json has empty files and include arrays. This is a common pattern for solution-style projects that only coordinate references.

Base Configuration

From src/tsconfig-base.json:
src/tsconfig-base.json

Compiler Project

From src/compiler/tsconfig.json:
src/compiler/tsconfig.json

Services Project (with Dependencies)

From src/services/tsconfig.json:
src/services/tsconfig.json
The services project depends on compiler and jsTyping, so it references them. TypeScript ensures they’re built first.

Composite Project Requirements

When composite: true is enabled, TypeScript enforces several requirements:

1. Must Specify Files

The project must specify which files are included using files, include, or both.

2. Must Enable Declaration Files

declaration is automatically set to true (unless explicitly disabled, which is not recommended).

3. RootDir Constraints

All files must be within the rootDir (if specified) or within the directory containing tsconfig.json.

Build Mode Commands

Project references work with TypeScript’s build mode:

Basic Build

Builds the project and all its dependencies.

Clean Build

Deletes output files for the project and all dependencies.

Force Rebuild

Forces a rebuild of all projects, regardless of whether they appear up-to-date.

Verbose Output

Shows detailed information about what’s being built.

Dry Run

Shows what would be built without actually building.

Watch Mode

Watches for changes and rebuilds incrementally.

Monorepo Structure

Project references are ideal for monorepo setups:

Root Configuration

tsconfig.json

Shared Package

packages/shared/tsconfig.json

Client Package (depends on shared)

packages/client/tsconfig.json

Web App (depends on client and shared)

apps/web/tsconfig.json

Import Behavior

When using project references, TypeScript uses the .d.ts files from referenced projects instead of the source .ts files:

Prepend Option

For outFile builds, you can use the prepend option:
This includes the referenced project’s output before the current project’s output in the final bundle.

Build Information Files

With project references, TypeScript generates .tsbuildinfo files:
These files contain:
  • Hashes of source files
  • Compiler options used
  • Output file locations
  • Dependency information
Don’t delete .tsbuildinfo files manually. Use tsc --build --clean to clean projects properly.

Performance Benefits

Before Project References

With Project References

Incremental Compilation

Project references enable true incremental compilation:
  1. File-level tracking: Only rebuild changed files
  2. Project-level tracking: Only rebuild changed projects
  3. Dependency tracking: Only rebuild dependent projects when needed

Editor Integration

Modern editors leverage project references for better performance:

VS Code

  • Automatically detects project references
  • Provides faster IntelliSense
  • Enables cross-project navigation
  • Shows build status for each project

Configuration for VS Code

.vscode/settings.json

Best Practices

Use composite mode

Always set "composite": true for projects that will be referenced.

Enable declarations

Ensure declaration is enabled (it’s automatic with composite).

Organize logically

Structure projects by logical boundaries (features, layers, etc.).

Minimize references

Only reference what you actually depend on to keep builds fast.

Common Patterns

Library + App

Multi-tier Architecture

Test Separation

Troubleshooting

Build Order Issues

Check your references for circular dependencies:
Solution: Restructure to eliminate cycles or extract shared code.
Ensure:
  1. Referenced project has composite: true
  2. Referenced project has been built (tsc --build)
  3. Path in reference is correct
  1. Check .tsbuildinfo files exist
  2. Verify incremental: true is set
  3. Ensure outDir is consistent
  4. Try tsc --build --force for a fresh rebuild

Declaration File Issues

Common issues:
  • Missing declaration: true
  • Files outside rootDir
  • Incorrect outDir configuration

Advanced Configuration

Disable Source File Preference

This forces TypeScript to always use .d.ts files from references, even when source files are available.

Disable Solution Searching

Prevents TypeScript from searching for a containing solution tsconfig.json.

Disable Referenced Project Load

Reduces the number of projects loaded automatically, improving editor performance for very large monorepos. Source: src/compiler/commandLineParser.ts:1487-1509

Migration Guide

Converting to Project References

  1. Identify natural boundaries in your codebase
  2. Create separate tsconfig.json for each project
  3. Enable composite mode in each tsconfig.json
  4. Add references between dependent projects
  5. Test the build with tsc --build
  6. Update package.json scripts

Example Migration

Before:
After:
tsconfig.json
lib/tsconfig.json
src/tsconfig.json

tsconfig.json

Learn about the complete tsconfig.json structure

Compiler Options Reference

Complete reference of all compiler options