Skip to main content

Performance Optimization

TypeScript offers several advanced features and compiler options designed to optimize compilation performance, especially for large projects. Understanding these options can significantly reduce build times.

Incremental Compilation

Incremental compilation allows TypeScript to save information about the project graph from the last compilation to speed up subsequent builds.

Enabling Incremental Mode

tsconfig.json
{
  "compilerOptions": {
    "incremental": true,
    "tsBuildInfoFile": "./.tsbuildinfo"
  }
}
The incremental flag is automatically enabled when composite is set to true.

How It Works

When incremental compilation is enabled, TypeScript:
  1. Saves a .tsbuildinfo file containing information about the project structure
  2. Tracks which files have changed since the last compilation
  3. Only recompiles affected files and their dependents
  4. Reuses type information from unchanged files
The .tsbuildinfo file stores:
  • File hashes and timestamps
  • Program structure information
  • Semantic diagnostics
  • Emit signatures

Customizing the Build Info File

tsconfig.json
{
  "compilerOptions": {
    "incremental": true,
    "tsBuildInfoFile": "./build/.tsbuildinfo"
  }
}
Add .tsbuildinfo to your .gitignore file - these files are build artifacts and should not be committed.

Project References

Project references enable TypeScript to work with multiple interconnected projects efficiently, allowing for faster builds and better code organization.

Setting Up Project References

Root Project:
tsconfig.json
{
  "files": [],
  "references": [
    { "path": "./packages/core" },
    { "path": "./packages/utils" },
    { "path": "./packages/app" }
  ]
}
Referenced Project:
packages/core/tsconfig.json
{
  "compilerOptions": {
    "composite": true,
    "declaration": true,
    "declarationMap": true,
    "outDir": "./dist"
  },
  "include": ["src/**/*"]
}

The composite Option

The composite option enables constraints that allow a TypeScript project to be used with project references:
tsconfig.json
{
  "compilerOptions": {
    "composite": true,
    "declaration": true,
    "declarationMap": true,
    "rootDir": "./src",
    "outDir": "./dist"
  }
}
Composite projects automatically enable incremental and require declaration to be true.

Benefits of Project References

Faster Builds

Only rebuild changed projects and their dependents

Better Structure

Enforce logical separation between project components

Editor Performance

Improved IDE responsiveness in large codebases

Parallel Builds

Independent projects can be built concurrently

Building with Project References

# Build the entire project graph
tsc --build

# Clean build outputs
tsc --build --clean

# Force rebuild all projects
tsc --build --force

# Watch mode with project references
tsc --build --watch

Watch Mode Optimizations

Watch mode monitors source files and recompiles when changes are detected. TypeScript includes several optimizations to make watch mode efficient.

Basic Watch Configuration

tsconfig.json
{
  "compilerOptions": {
    "incremental": true
  },
  "watchOptions": {
    "watchFile": "useFsEvents",
    "watchDirectory": "useFsEvents",
    "fallbackPolling": "dynamicPriority",
    "synchronousWatchDirectory": true,
    "excludeDirectories": ["**/node_modules", "_build"],
    "excludeFiles": ["build/fileWhichChangesOften.ts"]
  }
}

Watch Strategy Options

  • useFsEvents: Use the operating system’s file watching mechanism (recommended)
  • useFsEventsOnParentDirectory: Watch parent directories to reduce file watchers
  • dynamicPriorityPolling: Less frequent polling for less frequently changed files
  • fixedPollingInterval: Check files at fixed intervals
  • priorityPollingInterval: Use heuristics to check files at different intervals
  • useFsEvents: Use OS native directory watching (default on most systems)
  • dynamicPriorityPolling: Dynamic polling based on directory change frequency
  • fixedPollingInterval: Fixed interval polling for all directories

Watch Mode Performance Tips

tsconfig.json
{
  "watchOptions": {
    // Exclude large directories that don't need watching
    "excludeDirectories": [
      "**/node_modules",
      "**/.git",
      "**/dist",
      "**/build"
    ],
    
    // Exclude specific files that change frequently but don't need recompilation
    "excludeFiles": [
      "**/temp/**",
      "**/*.log"
    ]
  }
}
Use preserveWatchOutput: true to keep previous console output visible when files change.

Performance Compiler Options

skipLibCheck

Skip type checking of declaration files (.d.ts) to significantly improve compilation speed:
tsconfig.json
{
  "compilerOptions": {
    "skipLibCheck": true
  }
}
This is one of the most impactful performance optimizations. It’s enabled by default in many starter configurations.
When to use:
  • Large projects with many dependencies
  • When you trust the type definitions in node_modules
  • To reduce initial compilation time
Trade-offs:
  • May miss type errors in third-party declarations
  • Errors in .d.ts files won’t be reported

assumeChangesOnlyAffectDirectDependencies

In watch and incremental mode, assume changes only affect files that directly import the changed file:
tsconfig.json
{
  "compilerOptions": {
    "incremental": true,
    "assumeChangesOnlyAffectDirectDependencies": true
  }
}
This can lead to incomplete type checking in some scenarios. Use with caution.

disableSourceOfProjectReferenceRedirect

When referencing composite projects, use declaration files instead of source files:
tsconfig.json
{
  "compilerOptions": {
    "disableSourceOfProjectReferenceRedirect": true
  }
}
This can improve performance when:
  • Working in large monorepos
  • Referenced projects are stable
  • You don’t need to navigate to source in referenced projects
tsconfig.json
{
  "compilerOptions": {
    // Skip checking files that are definitely unaffected
    "skipDefaultLibCheck": true,
    
    // Disable size/performance optimizations for faster builds
    "preserveConstEnums": false,
    
    // Faster emit by not checking that files can be transpiled in isolation
    "isolatedModules": true,
    
    // Faster for large projects with many files
    "moduleDetection": "force"
  }
}

Measuring Performance

TypeScript provides built-in tools to measure compilation performance.

Using —diagnostics

tsc --diagnostics
Output:
Files:            250
Lines:            50000
Nodes:            180000
Identifiers:      65000
Symbols:          45000
Types:            15000
Memory used:      150000K
I/O read:         0.50s
I/O write:        0.10s
Parse time:       1.20s
Bind time:        0.80s
Check time:       3.50s
Emit time:        0.90s
Total time:       6.40s

Using —extendedDiagnostics

tsc --extendedDiagnostics
Provides detailed breakdown of:
  • Time spent in each compilation phase
  • Memory usage per phase
  • File I/O statistics
  • Type checking time per file

Performance Trace

Generate a detailed performance trace:
tsc --generateTrace ./trace
This creates trace files that can be analyzed with:
cd trace
python -m http.server 8080
# Open chrome://tracing and load trace.json

Best Practices

1

Enable incremental compilation

Use "incremental": true for all projects
2

Use project references for monorepos

Split large codebases into composite projects
3

Enable skipLibCheck

Skip type checking of declaration files
4

Configure watch options

Exclude unnecessary directories from file watching
5

Measure and optimize

Use --diagnostics to identify bottlenecks

Common Performance Issues

  • Enable skipLibCheck
  • Use types to include only needed @types packages
  • Consider splitting into project references
  • Check if .tsbuildinfo is being preserved
  • Verify watch mode exclusions are set correctly
  • Consider assumeChangesOnlyAffectDirectDependencies
  • Split project using project references
  • Enable isolatedModules if using a bundler
  • Check for circular dependencies
  • Use project references to scope type checking
  • Enable disableSourceOfProjectReferenceRedirect
  • Consider workspace-level excludes

Compiler Options

Complete compiler options reference

Project References

Multi-project setup and configuration

Build docs developers (and LLMs) love