Monorepos are a popular way to organize multiple related projects in a single
repository. They simplify dependency management, make it easier to refactor
across boundaries, and streamline the development process. However, managing
TypeScript configurations in a monorepo can become cumbersome without
a systematic approach. This blog post will guide you through setting up and
managing TypeScript configurations (tsconfig.json files) in a monorepo for
different types of projects, such as libraries, Node.js applications,
and React applications.
The Challenge
In a monorepo, projects often share common TypeScript configurations, such as compiler options and library inclusions. However, certain projects, like a React application vs. a Node.js service, require specific TypeScript configurations. Manually copying configurations between projects is error-prone and hard to maintain. The solution? Abstract common configurations into base configuration files and extend them in individual projects.
Structuring Your Monorepo
Consider a monorepo structure where your TypeScript configuration templates
live under a tools/tsconfig directory, and your projects are organized under
packages, categorized into apps and modules:
monorepo/
├── packages/
│   ├── apps/
│   │   ├── api/ (Node.js app)
│   │   └── react-app/ (React app)
│   └── modules/
│       └── my-module/ (Shared library)
└── tools/
    └── tsconfig/
        ├── tsconfig.base.json
        ├── tsconfig.library.json
        ├── tsconfig.node-app.json
        └── tsconfig.react-app.jsonBase TypeScript Configurations
tsconfig.base.json - The Core Configuration
This file contains compiler options common across all projects.
{
  "compilerOptions": {
    "target": "es2020",
    "module": "esnext",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "baseUrl": "."
  },
  "exclude": ["node_modules"]
}Specialized Configurations
tsconfig.library.json for Libraries
{
  "extends": "@monorepo/tsconfig/tsconfig.base.json",
  "compilerOptions": {
    "declaration": true,
    "outDir": "./lib"
  },
  "include": ["src/**/*"]
}tsconfig.node-app.json for Node.js Applications
{
  "extends": "@monorepo/tsconfig/tsconfig.base.json",
  "compilerOptions": {
    "outDir": "./dist",
    "module": "commonjs"
  },
  "include": ["src/**/*"]
}tsconfig.react-app.json for React Applications
{
  "extends": "@monorepo/tsconfig/tsconfig.base.json",
  "compilerOptions": {
    "jsx": "react-jsx",
    "lib": ["dom", "dom.iterable", "esnext"]
  },
  "include": ["src/**/*"]
}Project Configuration Examples
Projects extend the appropriate base configuration.
Here's how a tsconfig.json in the React app would look:
{
  "extends": "@monorepo/tsconfig/tsconfig.react-app.json",
  "compilerOptions": {
    "baseUrl": "./src"
  },
  "include": ["src/**/*"]
}Conclusion
This setup simplifies managing TypeScript configurations in a monorepo by centralizing common settings and allowing for project-specific overrides. By abstracting these configurations into a package, we ensure consistency across projects and ease the maintenance burden. As your monorepo grows, this approach scales efficiently, allowing you to focus on development rather than configuration management.
