microsoft/TypeScript
Project references
The mechanism by which a TypeScript codebase splits into smaller, mutually-referencing compilations that can be built independently and consumed via their .d.ts outputs.
Where project references touch the codebase
| Subsystem | File | Role |
|---|---|---|
| Config parsing | src/compiler/commandLineParser.ts |
Parses references array, validates project paths |
| Solution builder | src/compiler/tsbuildPublic.ts |
Topological build order, up-to-date checks, multi-project compile |
| Solution-builder types | src/compiler/tsbuild.ts |
BuildOptions, UpToDateStatus |
| Program | src/compiler/program.ts |
redirectedReference plumbing for cross-project type references |
| Builder | src/compiler/builder.ts |
.tsbuildinfo shape with cross-project info |
Concept
A tsconfig.json declares dependencies on other projects:
{
"compilerOptions": {
"composite": true,
"outDir": "./out"
},
"references": [{ "path": "../shared" }, { "path": "../utils" }]
}composite: true enables --declaration, --declarationMap, --incremental, and disallows --noEmit. References point at directories containing other tsconfig.jsons.
When tsc -b is run, the solution builder:
- Loads the root
tsconfig.jsonand recursively followsreferences. - Topologically sorts the resulting DAG.
- For each project in order, asks: is this project up-to-date? If not, build it.
- Writes
.tsbuildinfoper project so subsequent runs can short-circuit.
When a downstream Program resolves a reference to an upstream project's source, it transparently uses the upstream's .d.ts outputs instead — sources cross project boundaries only at type-level.
Up-to-date checks
getUpToDateStatusOfProject reads a project's .tsbuildinfo and decides one of:
UpToDate— skipOutOfDateWithSelf— own sources changedOutOfDateWithUpstream— an upstream project rebuiltOutOfDateBuildInfo—.tsbuildinfomissing or unparseableOutOfDateOptions—CompilerOptionschanged since last buildUpstreamOutOfDate/UpstreamBlocked— an upstream project itself isn't ready
These statuses give clear diagnostic output (e.g., Project '/abs/foo/tsconfig.json' is out of date because output 'foo.js' is older than input 'foo.ts') so users can debug build invalidations.
Cross-project resolution
When a downstream file imports "../shared/Logger":
- The resolver detects the import lands inside a referenced project.
- It substitutes the resolved file with the upstream's emitted
.d.ts(under that project'soutDirordeclarationDir). - The downstream program records a
redirectedReferencemapping so the checker can correlate symbols across the boundary.
This means upstream projects' implementation files are never loaded into a downstream's type system — only their declarations.
Watch mode for build
tsc -b --watch (and the editor case via tsserver with project references) keeps the solution builder alive, watches every project's files, and rebuilds in topological order whenever a relevant change comes in. Cascading invalidation respects the up-to-date status — a leaf project change doesn't force re-checking unrelated projects unless their inputs depend on the changed outputs.
Diagnostics specific to references
- TS6377: Cannot write file because it would overwrite input file — when project A's
outDirlands inside project B's source set. - TS6378: Project references may not form a circular graph — cycle detection.
- TS6306: Referenced project '{0}' must have setting "composite": true. — composite is mandatory.
- TS6310: Referenced project '{0}' may not disable emit. —
noEmit: trueis incompatible with being depended upon.
Tests
tests/cases/projects/ contains many multi-project fixtures, often with explicit referencesFiles setups. The tsbuild runner exercises them and compares against baselines.
Entry points for modification
- Up-to-date logic:
tsbuildPublic.ts, specificallygetUpToDateStatusWorker. - Build options: extend
BuildOptionsintsbuild.tsand wire CLI flags inexecuteCommandLine.ts. .tsbuildinfoshape:builder.ts— be careful, this format is a versioned on-disk contract.
See systems/build-mode and systems/watch-and-builder for the underlying primitives, and features/declaration-emit for what crosses project boundaries.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.