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.json
Base 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.