This TypeScript error occurs when using project references and the referenced project has been modified without rebuilding. TypeScript needs to rebuild the referenced project to ensure type information is up-to-date. Running `tsc --build` or `tsc -b` will rebuild all referenced projects.
The "Project reference is stale" error appears when you're using TypeScript's project references feature and a referenced project has changed since it was last built. TypeScript project references allow you to structure large codebases into multiple TypeScript projects that depend on each other. When Project A references Project B, TypeScript needs to know the compiled output and type information from Project B. If you modify files in Project B but don't rebuild it, Project A will see outdated type information, leading to this error. This is a safety feature that ensures type consistency across your entire codebase. TypeScript detects when referenced projects have been modified and requires a rebuild before continuing compilation.
The simplest fix is to run tsc --build (or tsc -b) from the root of your project:
# Rebuild all projects in the solution
tsc --build
# Or with shorter syntax
tsc -b
# If you have a specific tsconfig.json for building
tsc --build tsconfig.json
# For incremental builds (faster)
tsc --build --incrementalThe --build flag tells TypeScript to:
1. Detect all project references
2. Build them in the correct dependency order
3. Update .tsbuildinfo files to track build state
4. Ensure type consistency across all projects
After running this command, try compiling your main project again.
If tsc --build doesn't resolve the issue, try cleaning the build artifacts first:
# Clean all build outputs
tsc --build --clean
# Then rebuild
tsc --build
# Or combine in one command
tsc --build --clean --forceThis removes:
- Compiled .js and .d.ts files
- .tsbuildinfo files
- Any cached build information
After cleaning, TypeScript will perform a fresh build of all projects.
Ensure your tsconfig.json files have correct project references configuration:
// tsconfig.json (root or main project)
{
"compilerOptions": {
"composite": true,
"declaration": true,
"declarationMap": true,
"outDir": "./dist"
},
"references": [
{ "path": "./packages/core" },
{ "path": "./packages/utils" }
]
}
// packages/core/tsconfig.json
{
"compilerOptions": {
"composite": true,
"declaration": true,
"declarationMap": true,
"outDir": "../../dist/core"
}
}
// packages/utils/tsconfig.json
{
"compilerOptions": {
"composite": true,
"declaration": true,
"declarationMap": true,
"outDir": "../../dist/utils"
}
}Key requirements:
- All referenced projects must have "composite": true
- All referenced projects must have "declaration": true
- Output directories should not overlap
- References use relative paths to project directories
Create proper build scripts to avoid manual tsc --build commands:
// package.json
{
"scripts": {
"build": "tsc --build",
"build:clean": "tsc --build --clean",
"build:watch": "tsc --build --watch",
"build:incremental": "tsc --build --incremental",
"clean": "tsc --build --clean"
}
}Then use:
npm run build # Standard build
npm run build:watch # Watch mode for development
npm run clean # Clean build artifactsFor monorepos with multiple packages:
{
"scripts": {
"build": "npm run build --workspaces",
"build:packages": "npm run build --workspace=packages/*"
}
}Verify these common configuration problems:
1. Missing composite flag:
// WRONG - missing composite
{
"compilerOptions": {
"declaration": true
}
}
// CORRECT
{
"compilerOptions": {
"composite": true,
"declaration": true
}
}2. Overlapping output directories:
// WRONG - projects output to same directory
{
"compilerOptions": {
"outDir": "../dist"
}
}
// CORRECT - unique output directories
{
"compilerOptions": {
"outDir": "../dist/core"
}
}3. Incorrect reference paths:
// WRONG - references tsconfig.json file directly
{
"references": [
{ "path": "./packages/core/tsconfig.json" }
]
}
// CORRECT - references directory
{
"references": [
{ "path": "./packages/core" }
]
}4. Missing declaration files:
- Ensure "declaration": true is set
- Check that .d.ts files are being generated
- Verify .d.ts files are in the correct output directory
During development, use watch mode to automatically rebuild when files change:
# Watch all projects
tsc --build --watch
# Watch with specific tsconfig
tsc --build tsconfig.json --watch
# Watch with incremental builds
tsc --build --watch --incremental
# In package.json scripts
{
"scripts": {
"dev": "tsc --build --watch",
"dev:incremental": "tsc --build --watch --incremental"
}
}Watch mode benefits:
- Automatically rebuilds when any source file changes
- Maintains correct build order across projects
- Shows compilation errors in real-time
- Faster than manual builds with incremental compilation
For CI/CD pipelines, ensure you run tsc --build before any type checking or testing.
### Understanding .tsbuildinfo Files
TypeScript uses .tsbuildinfo files to track build state for composite projects. These files contain:
- Timestamps of source files
- Compiler options used
- Dependency graph between files
- Build signatures for incremental compilation
When you modify a source file, TypeScript compares its timestamp against the .tsbuildinfo file. If they don't match, the project is marked as "stale".
### Solution Reference Mode vs Build Mode
TypeScript has two modes for project references:
Solution Reference Mode (default with tsc):
- Only type-checks projects
- Assumes referenced projects are already built
- Fails with "stale" error if referenced projects changed
Build Mode (tsc --build):
- Builds projects in dependency order
- Updates .tsbuildinfo files
- Handles stale references automatically
- Required for composite projects
### Common Pitfalls
1. Mixed build tools: Using both tsc --build and other build tools (webpack, esbuild) can cause conflicts. Ensure all tools use the same build artifacts.
2. Git operations: Git operations that modify timestamps (checkout, reset) can trigger stale errors. Run tsc --build after such operations.
3. IDE integration: Some IDEs may run tsc instead of tsc --build. Configure your IDE to use build mode:
- VS Code: Set "typescript.tsdk" and use Build Task
- WebStorm: Configure TypeScript compiler with --build flag
4. Monorepo tools: If using Lerna, Nx, or Turborepo, ensure they call tsc --build not tsc.
### Performance Considerations
- Incremental builds: Use --incremental flag for faster rebuilds
- Parallel builds: TypeScript builds projects in parallel when possible
- Memory usage: Large projects may need increased Node.js memory limit: NODE_OPTIONS=--max-old-space-size=4096
### Debugging
To debug project reference issues:
# Verbose output showing build steps
tsc --build --verbose
# List all project references
tsc --build --dry
# Show dependency graph
tsc --build --listFiles
# Check specific project
tsc --project packages/core --showConfigFunction expression requires a return type
Function expression requires a return type
Value of type 'string | undefined' is not iterable
How to fix "Value is not iterable" in TypeScript
Type 'undefined' is not assignable to type 'string'
How to fix "Type undefined is not assignable to type string" in TypeScript
Type narrowing from typeof check produces 'never'
How to fix "Type narrowing produces never" in TypeScript
Type parameter 'T' has conflicting constraints
How to fix "Type parameter has conflicting constraints" in TypeScript