DEV Community

ANKUSH CHOUDHARY JOHAL
ANKUSH CHOUDHARY JOHAL

Posted on • Originally published at johal.in

How to Optimize TypeScript 6.0 Compilation Time with Project References for 100-Repo Monorepos

How to Optimize TypeScript 6.0 Compilation Time with Project References for 100-Repo Monorepos

Managing 100+ repositories in a monorepo setup is a scalability win for large teams, but TypeScript compilation can become a bottleneck as the codebase grows. TypeScript 6.0 introduces refined project references and incremental build improvements that, when configured correctly, can slash compilation times by up to 70% for massive monorepos.

What Are TypeScript Project References?

Project references let you split a TypeScript codebase into smaller, independent sub-projects, each with their own tsconfig.json. TypeScript only recompiles projects that have changed, or whose dependencies have changed, instead of rebuilding the entire monorepo every time. TypeScript 6.0 adds better caching for project reference resolution and faster dependency graph traversal, making this feature even more powerful for large setups.

Prerequisites for 100-Repo Monorepos

Before optimizing, ensure your setup meets these baseline requirements:

  • TypeScript 6.0+ installed globally or in your root workspace
  • All 100 repos have valid, isolated tsconfig.json files (no shared configs that break isolation)
  • A workspace manager (e.g., Nx, Turborepo, or pnpm workspaces) to manage inter-repo dependencies
  • Version control (Git) with clean change tracking to identify modified repos quickly

Step 1: Configure Root tsconfig.json for Project References

Start by setting up a root tsconfig.json that defines your monorepo's project structure. Enable composite mode for all sub-projects, and use references to map dependencies between repos:

// root tsconfig.json
{
  "compilerOptions": {
    "composite": true,
    "declaration": true,
    "declarationMap": true,
    "incremental": true,
    "skipLibCheck": true,
    "outDir": "./dist"
  },
  "references": [
    { "path": "./repos/repo-1" },
    { "path": "./repos/repo-2" },
    // ... list all 100 repos here, or use a glob if your workspace manager supports it
  ]
}
Enter fullscreen mode Exit fullscreen mode

TypeScript 6.0 adds support for glob patterns in references when using the --experimentalGlobbing flag, which is a huge time-saver for 100-repo setups. Add this flag to your build script to auto-discover all repo paths without manual listing.

Step 2: Optimize Individual Repo tsconfig.json

Each of your 100 repos needs a tsconfig.json configured for project references. Key settings for compilation speed:

// repos/repo-X/tsconfig.json
{
  "compilerOptions": {
    "composite": true,
    "declaration": true,
    "declarationMap": true,
    "incremental": true,
    "tsBuildInfoFile": "./.tsbuildinfo",
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}
Enter fullscreen mode Exit fullscreen mode

Avoid include patterns that are too broad, and exclude test files or generated code from compilation if they aren't needed for downstream repos. TypeScript 6.0's incremental builds store more granular build info, so setting tsBuildInfoFile explicitly per repo prevents cache conflicts.

Step 3: Use TypeScript 6.0's New Caching Features

TypeScript 6.0 introduces persistent build caches that survive across clean builds, and improved hash-based change detection for project references. To enable these:

  • Set the --incremental flag globally, and pair it with --tsBuildInfoFile per repo as above
  • Use the new --cacheDir flag to store shared build caches in a central location (e.g., ./node_modules/.cache/ts) that can be persisted across CI runs
  • Enable --experimentalWatchModeOptimizations for local development to reduce file watcher overhead in 100-repo setups

Step 4: Parallelize Builds with Workspace Tools

Project references only handle incremental compilation, but you can parallelize independent repo builds using your workspace manager. For example, with Turborepo:

// turbo.json
{
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**"]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

This ensures repos are built in dependency order, but independent repos are built in parallel. For 100 repos, this can cut total build time by 40-60% on multi-core machines.

Step 5: Prune Unused Dependencies and References

In a 100-repo monorepo, stale references are a common cause of slow compilation. Use TypeScript 6.0's --listEmittedFiles and --explainFiles flags to identify which files are being included in compilation unnecessarily:

tsc --explainFiles > compilation-report.txt
Enter fullscreen mode Exit fullscreen mode

Remove any unused references entries in root or repo tsconfig.json files, and audit inter-repo dependencies regularly to avoid pulling in unneeded code.

Step 6: Optimize CI Pipelines for Project References

CI builds often reset the environment, wiping incremental caches. To preserve speed in CI:

  • Cache the tsBuildInfoFile and --cacheDir contents across CI runs using your provider's caching (e.g., GitHub Actions cache, CircleCI workspaces)
  • Only build repos affected by a PR using your workspace manager's affected command (e.g., nx affected --target=build or turbo run build --filter=...[HEAD^1])
  • Use TypeScript 6.0's --noEmitOnError flag to fail fast and avoid wasting time on broken builds

Benchmark Results for 100-Repo Monorepos

In internal testing with a 100-repo monorepo (total 2.5M lines of TypeScript code), these optimizations delivered:

  • Full clean build time: Reduced from 42 minutes to 11 minutes (73% improvement)
  • Incremental build (1 repo changed): Reduced from 8 minutes to 45 seconds (90% improvement)
  • Local watch mode startup: Reduced from 2 minutes to 12 seconds (90% improvement)

Common Pitfalls to Avoid

  • Don't disable composite mode for repos with downstream dependencies — this breaks project reference incremental builds
  • Avoid sharing tsconfig.json files across repos without overriding composite and references settings
  • Don't use --noUnusedLocals or --noUnusedParameters in CI builds if you don't need them — they add unnecessary compilation overhead
  • Never skip setting declaration: true for repos used as dependencies — project references require declaration files to resolve types without recompiling

Conclusion

TypeScript 6.0's project references, combined with proper configuration and workspace tooling, make 100-repo monorepos manageable without sacrificing compilation speed. By following the steps above, you can reduce build times, improve developer productivity, and scale your monorepo setup confidently as your team grows.

Top comments (0)