This TypeScript error occurs when a project reference in tsconfig.json points to a directory instead of a tsconfig.json file. Project references must explicitly reference tsconfig.json files to enable proper incremental builds and cross-project type checking. The fix involves correcting the reference path to include '/tsconfig.json' at the end.
The "Project reference path must point to tsconfig.json" error (TS6306) appears when TypeScript encounters an invalid project reference in your tsconfig.json file. Project references are a TypeScript feature that allows you to structure your codebase into multiple projects that can reference each other, enabling incremental builds and better performance. When you specify a project reference, TypeScript expects the path to point directly to a tsconfig.json file, not just a directory. This is because TypeScript needs to know exactly which configuration file to use for the referenced project. The error typically occurs when you write: ```json { "references": [ { "path": "./packages/shared" } // WRONG - missing tsconfig.json ] } ``` Instead of: ```json { "references": [ { "path": "./packages/shared/tsconfig.json" } // CORRECT ] } ``` This error prevents TypeScript from setting up proper project dependencies, which can break incremental compilation, cross-project type checking, and build optimizations.
Check your tsconfig.json file and ensure all project references point to tsconfig.json files:
// WRONG - points to directory
{
"references": [
{ "path": "./packages/shared" },
{ "path": "../utils" }
]
}
// CORRECT - points to tsconfig.json file
{
"references": [
{ "path": "./packages/shared/tsconfig.json" },
{ "path": "../utils/tsconfig.json" }
]
}The path can be:
- Relative: "./packages/shared/tsconfig.json"
- Absolute: "/home/user/project/packages/shared/tsconfig.json"
- Using path aliases if configured in compilerOptions.paths
After fixing, try building:
npx tsc --build
# or
npm run buildVerify that the tsconfig.json file actually exists at the referenced path:
# Check if file exists
ls -la ./packages/shared/tsconfig.json
# For Windows PowerShell
Test-Path ./packages/shared/tsconfig.json
# If using a monorepo, check common locations:
find . -name "tsconfig.json" -type f | grep -v node_modules
# Common tsconfig.json naming patterns:
# - tsconfig.json (main)
# - tsconfig.build.json (build-specific)
# - tsconfig.test.json (test-specific)
# - tsconfig.lib.json (library-specific)If the file doesn't exist, you need to:
1. Create it: touch ./packages/shared/tsconfig.json
2. Copy from another project: cp ./tsconfig.json ./packages/shared/
3. Or create a minimal config:
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist"
},
"include": ["src/**/*"]
}Ensure the path correctly resolves from your current tsconfig.json location:
// Project structure:
// - tsconfig.json (root)
// - packages/
// - shared/
// - tsconfig.json
// WRONG - incorrect relative path
{
"references": [
{ "path": "packages/shared/tsconfig.json" } // Missing ./
]
}
// CORRECT
{
"references": [
{ "path": "./packages/shared/tsconfig.json" }
]
}
// If using path aliases from baseUrl:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@shared/*": ["packages/shared/src/*"]
}
},
"references": [
{ "path": "./packages/shared/tsconfig.json" } // Still use file path, not alias
]
}Debug path resolution:
# Check what the path resolves to
node -e "console.log(require('path').resolve(__dirname, './packages/shared/tsconfig.json'))"
# In TypeScript, you can check with:
npx tsc --showConfigIn monorepos, you might have multiple tsconfig.json files. Ensure references point to the correct one:
// Root tsconfig.json
{
"references": [
{ "path": "./packages/shared/tsconfig.json" },
{ "path": "./packages/ui/tsconfig.json" },
{ "path": "./apps/web/tsconfig.json" }
]
}
// packages/shared/tsconfig.json
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"composite": true, // Required for project references
"declaration": true,
"declarationMap": true,
"outDir": "./dist"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}Key requirements for referenced projects:
1. "composite": true - Marks project as referenceable
2. "declaration": true - Generates .d.ts files
3. "declarationMap": true - Optional but helpful for debugging
4. Proper "outDir" configuration
Verify with:
# Build all referenced projects
npx tsc --build
# Build specific project
npx tsc --build packages/shared
# Clean builds
npx tsc --build --cleanAfter fixing references, update your build scripts:
// package.json
{
"scripts": {
"build": "tsc --build",
"build:watch": "tsc --build --watch",
"build:clean": "tsc --build --clean",
"type-check": "tsc --noEmit",
// For specific projects
"build:shared": "tsc --build packages/shared",
"build:ui": "tsc --build packages/ui"
}
}For CI/CD pipelines:
# GitHub Actions example
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- run: npm ci
- run: npm run build # Uses tsc --build
- run: npm testCommon pitfalls to avoid:
- Don't run tsc without --build flag on root config with references
- Ensure all developers have same TypeScript version
- Clear TypeScript cache if issues persist: rm -rf .tsbuildinfo
After making changes, verify everything works:
# 1. Clean previous builds
npx tsc --build --clean
# 2. Build all projects
npx tsc --build
# 3. Check for any remaining errors
npx tsc --noEmit
# 4. Test incremental builds
npx tsc --build --watch &
# Make a change in a referenced project
# Should only rebuild affected projects
# 5. Verify cross-project type checking works
# Create a file that imports from referenced project
echo 'import { something } from "@shared";' > test.ts
npx tsc --noEmit test.tsIf issues persist:
- Check TypeScript version: npx tsc --version
- Ensure no circular references between projects
- Check for symlink issues in monorepos
- Verify all tsconfig.json files have "composite": true
For complex setups, consider:
- Using a build tool like Turborepo, Nx, or Lerna
- Configuring project references incrementally
- Setting up CI cache for .tsbuildinfo files
### Understanding Project References
Project references enable TypeScript's build mode (tsc --build), which provides:
1. Incremental compilation: Only rebuild changed projects
2. Cross-project type checking: Type safety across project boundaries
3. Output organization: Each project builds to its own output directory
4. Dependency ordering: Automatic build order based on references
### Composite Projects Requirements
Referenced projects must have:
{
"compilerOptions": {
"composite": true, // Required
"declaration": true, // Required
"declarationMap": true, // Recommended
"outDir": "./dist", // Should be set
"rootDir": "./src" // Recommended for clarity
}
}### Solution Reference Cycles
Avoid circular references:
// Project A references B
// Project B references A // CIRCULAR - will failIf you need bidirectional type access, consider:
1. Creating a third "common" project with shared types
2. Using declaration merging
3. Restructuring to avoid the cycle
### Build Info Files
When using tsc --build, TypeScript creates .tsbuildinfo files that track:
- File hashes for incremental builds
- Project dependencies
- Build state
These should be:
- Committed to git (for reproducible builds)
- Cached in CI/CD
- Not manually edited
### Monorepo Best Practices
For large monorepos:
1. Base configuration: tsconfig.base.json with shared settings
2. Project references: Explicit dependencies between projects
3. Path aliases: Use paths for clean imports within workspace
4. Build tools: Consider Turborepo or Nx for advanced caching
Example structure:
tsconfig.base.json # Shared compiler options
tsconfig.json # Root with references
packages/
shared/
tsconfig.json # Extends base, composite: true
src/
dist/
ui/
tsconfig.json # References shared
apps/
web/
tsconfig.json # References shared, ui### Debugging Tips
1. Verbose output: tsc --build --verbose
2. Trace resolution: tsc --build --traceResolution
3. Show config: tsc --showConfig
4. Dry run: tsc --build --dry
### Migration from Single Project
When migrating a large codebase to project references:
1. Start with leaf projects (no dependencies)
2. Add "composite": true and fix errors
3. Update root tsconfig.json with references
4. Switch from tsc to tsc --build
5. Update CI/CD and developer tooling
### Common Pitfalls
1. Missing tsconfig.json: Referenced project must have config file
2. No composite flag: Required for all referenced projects
3. Path case sensitivity: Matters on Linux/macOS
4. Symlink issues: In monorepos with npm/yarn workspaces
5. IDE support: VS Code may need reload after changing references
### Performance Considerations
Project references improve build performance by:
- Skipping unchanged projects
- Parallel building of independent projects
- Caching type checking results
- Incremental .d.ts file generation
For very large codebases, consider:
- Splitting into more granular projects
- Using solution-style tsconfig.json at root
- Implementing build caching with tools like Turborepo
Function 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