This page documents the incremental compilation system and the multi-project solution builder in the TypeScript compiler. It covers how the compiler tracks file state across builds, determines which files are affected by a change, persists that state to .tsbuildinfo files, and coordinates builds across multiple projects linked by project references.
For details on the underlying Program object and compilation lifecycle, see Compiler Architecture and Program and Compilation. For the watch mode integration used alongside incremental builds, see the watch section within this page and refer to tsserver Project Management for how the language server manages projects.
TypeScript exposes two related but distinct build acceleration mechanisms:
| Mechanism | Flag | Entry Point | Scope |
|---|---|---|---|
| Incremental compilation | --incremental | createIncrementalProgram | Single tsconfig.json |
| Solution builder | --build (tsc -b) | createSolutionBuilder | Multiple projects with references |
Both rely on the same underlying BuilderProgram abstraction and .tsbuildinfo persistence, but the solution builder adds a project-level dependency graph and up-to-date checking layer on top.
Incremental compilation wraps a normal Program with a BuilderProgram that tracks per-file content hashes (called signatures) and emits a .tsbuildinfo file after each successful build. On the next invocation, it reads that file back and reuses unchanged files without re-type-checking them.
The solution builder (SolutionBuilder) reads the references array from each tsconfig.json, performs a topological sort, checks each project's up-to-date status via UpToDateStatusType, and builds only the projects that are stale.
Sources: src/compiler/builder.ts1-10 src/compiler/tsbuild.ts1-50 src/compiler/emitter.ts431-504
BuilderProgram is the public interface for incremental programs. It extends the normal Program API with methods for incrementally computing affected files and diagnostics.
Two concrete variants are exposed publicly:
| Interface | Factory Function | Use Case |
|---|---|---|
SemanticDiagnosticsBuilderProgram | createSemanticDiagnosticsBuilderProgram | Language service / watch mode diagnostics |
EmitAndSemanticDiagnosticsBuilderProgram | createEmitAndSemanticDiagnosticsBuilderProgram | Watch mode emit |
Both are created via createBuilderProgram internally in src/compiler/builder.ts, which constructs the BuilderState and attaches it to the wrapping program object.
BuilderState (in src/compiler/builder.ts) is the internal data structure that tracks the state of every source file in the compilation. It stores:
fileInfos — A Map<Path, FileInfo> that records each file's current version (a hash of content) and computed type signature.referencedMap — A Map<Path, Set<Path>> representing which files import each file (the reverse dependency graph). See Dependency Graph below.exportedModulesMap — A Map<Path, Set<Path>> tracking which files export types visible across module boundaries.semanticDiagnosticsPerFile — Cached diagnostics per file to avoid recomputing them.affectedFiles — The current frontier of files that need re-checking after a change.File signature is the hash of a file's emitted .d.ts output (not its source text). If a file's source changes but its public API does not change, its signature stays the same, so downstream files do not need re-checking.
Sources: src/compiler/builder.ts1-50 src/server/project.ts9
When a file changes, the compiler does not simply re-check everything. The process is:
Affected-file resolution diagram
Sources: src/compiler/builder.ts1-50
referencedMapThe referencedMap is the core data structure driving the incremental re-check. It is a map from each file's Path to the set of file Paths that depend on it (i.e., files that directly import it).
When a file's signature changes, the compiler does a breadth-first traversal of this map to find all transitively affected files. Once all affected files are re-checked and their signatures stabilize, the traversal terminates.
referencedMap structure
The exportedModulesMap is a refinement of referencedMap: it only tracks files that export something the dependent actually uses in a type position. This lets the compiler prune the frontier further — a change to a private implementation detail does not invalidate importers even if the file's text hash changes.
Sources: src/compiler/builder.ts1-50
.tsbuildinfo FilesAfter a successful incremental build, the compiler serializes BuilderState into a .tsbuildinfo file. This JSON file acts as the persistent cache for the next invocation.
The path is computed by getTsBuildInfoEmitOutputFilePath in src/compiler/emitter.ts. The resolution order is:
options.tsBuildInfoFile — explicit overrideoutFile is set: <outFile-without-extension>.tsbuildinfoconfigFilePath using outDir and rootDir, with .tsbuildinfo extension appendedsrc/compiler/emitter.ts481-499
A file is recognized as a .tsbuildinfo file by isBuildInfoFile src/compiler/emitter.ts431-433 which checks for the Extension.TsBuildInfo extension (.tsbuildinfo).
Emission only occurs when canEmitTsBuildInfo returns true src/compiler/emitter.ts502-504 which is when isIncrementalCompilation(options) is true (i.e., --incremental is set) or options.tscBuild is set (used by the solution builder).
The .tsbuildinfo file stores a BuildInfo object, which includes:
| Field | Description |
|---|---|
program | Serialized ProgramBuildInfo: file names, file info, referenced map, exports map, diagnostics |
version | TypeScript compiler version that wrote the file |
bundle | Bundle information when outFile is used |
On the next run, if the .tsbuildinfo file is present and the TypeScript version matches, the compiler reads this state back and uses it to bootstrap BuilderState without a full re-analysis.
Build info serialization flow
Sources: src/compiler/emitter.ts431-504 src/compiler/builder.ts1-50
UpToDateStatusType EnumUpToDateStatusType is defined in src/compiler/tsbuild.ts and is used by the solution builder to determine whether a project needs to be rebuilt. Each project reference is checked independently before the solution builder decides what to do.
| Status | Meaning |
|---|---|
Unbuildable | Project has errors that prevent it from being built |
UpToDate | All outputs are newer than all inputs |
UpToDateWithUpstreamTypes | Outputs are older than upstream sources but not older than upstream .d.ts — a pseudo-build (timestamp touch) is sufficient |
OutputMissing | One or more output files do not exist |
OutOfDateWithSelf | An input source file is newer than the project's own outputs |
OutOfDateWithUpstream | An upstream project's outputs are newer than this project's outputs |
OutOfDateWithPrepend | Prepend inputs have changed |
ContainerOnly | Project has no buildable files — it is only a container of references |
ForceBuild | Build was explicitly forced (e.g., --force) |
The concept of UpToDateWithUpstreamTypes is important: if only the implementation (.js) of a dependency changed but its public API (.d.ts) is unchanged, the dependent project does not need a full rebuild. The solution builder just updates timestamps.
UpToDate status decision tree
Sources: src/compiler/tsbuild.ts10-50
The solution builder (SolutionBuilder<T>) is activated by tsc --build (or tsc -b). It reads tsconfig.json files, follows their references arrays, performs a topological sort, and builds each project in dependency order.
| Type / Function | File | Role |
|---|---|---|
SolutionBuilder<T> | src/compiler/tsbuild.ts | Top-level orchestrator for multi-project build |
createSolutionBuilder | src/compiler/tsbuild.ts | Factory for SolutionBuilder |
createSolutionBuilderWithWatch | src/compiler/tsbuild.ts | Solution builder with integrated watch mode |
SolutionBuilderHost<T> | src/compiler/types.ts | Host interface for solution builder I/O |
InvalidatedProject<T> | src/compiler/types.ts | Represents a single project that needs building |
BuildOptions | src/compiler/types.ts | Options controlling --build behavior (force, verbose, dry, etc.) |
UpToDateStatusType | src/compiler/tsbuild.ts | Status of each project in the graph |
Solution builder project orchestration
For the solution builder to work correctly, each referenced project must have composite: true in its tsconfig.json. This enforces:
declaration: true — .d.ts files must be emitted (they are the interface between projects)include/filesThe .d.ts outputs of each project are the inputs to downstream projects. The solution builder uses file modification timestamps and .tsbuildinfo signatures to decide whether to rebuild.
Sources: src/compiler/tsbuild.ts1-50 src/compiler/builder.ts1-50 src/compiler/emitter.ts431-504
The incremental builder integrates tightly with watch mode. createWatchProgram (in src/compiler/watch.ts) accepts a WatchCompilerHost<T extends BuilderProgram> and continuously rebuilds using the BuilderProgram to compute the minimal affected set after each file system event.
The solution builder also has a watch variant (createSolutionBuilderWithWatch) that watches all projects in the graph simultaneously and rebuilds dependent projects automatically when upstream .d.ts outputs change.
Component relationships
Sources: src/compiler/watch.ts1-30 src/compiler/builder.ts1-10 src/compiler/tsbuild.ts1-50
The following are the publicly exported entry points for incremental and project builds, accessible via the typescript npm package:
| Symbol | Kind | Description |
|---|---|---|
createIncrementalProgram | function | Creates a Program with .tsbuildinfo support |
createIncrementalCompilerHost | function | Creates a CompilerHost that reads .tsbuildinfo |
createSemanticDiagnosticsBuilderProgram | function | BuilderProgram for diagnostics-only workflows |
createEmitAndSemanticDiagnosticsBuilderProgram | function | BuilderProgram for emit + diagnostics |
createWatchProgram | function | Watch-mode program (uses BuilderProgram) |
createWatchCompilerHost | function | Host for watch-mode programs |
createSolutionBuilder | function | Multi-project build orchestrator |
createSolutionBuilderWithWatch | function | Multi-project build with watch |
BuilderProgram | interface | Base interface for incremental programs |
SemanticDiagnosticsBuilderProgram | interface | Extends BuilderProgram for diagnostics |
EmitAndSemanticDiagnosticsBuilderProgram | interface | Extends BuilderProgram for emit |
InvalidatedProject<T> | interface | A stale project pending rebuild |
SolutionBuilder<T> | interface | Solution-level build coordinator |
BuildOptions | interface | Options for --build mode |
UpToDateStatusType | enum | Freshness status of a project |
Sources: tests/baselines/reference/api/typescript.d.ts1-100 src/compiler/builder.ts1-10 src/compiler/tsbuild.ts1-50
Refresh this wiki
This wiki was recently refreshed. Please wait 4 days to refresh again.