DEV Community

Cover image for 🧩 How to Create a Reusable TypeScript Config Package in Turborepo
Saiful Islam
Saiful Islam

Posted on

🧩 How to Create a Reusable TypeScript Config Package in Turborepo

When working in a monorepo with multiple applications and packages, it's easy for your TypeScript config files to become redundant, inconsistent, or just plain messy. Fortunately, if you're using Turborepo, you can clean that up with a single, shareable TypeScript config package.

In this blog post, I’ll walk you through how to create a reusable @dtr-cli/typescript-config -- @dtr-cli is my project package, structure it for multiple project types (backend, frontend, Vite, Next.js etc.), and integrate it across your monorepo like a pro.

βœ… This approach is especially helpful for developers maintaining multiple apps in a monorepo using tools like Turborepo, pnpm workspaces, or Yarn workspaces.


🧩 Step-by-Step: Creating the @dtr-cli/typescript-config Package

1. Create a Package Folder

Inside your packages/ folder, create a new directory called typescript-config.

mkdir -p packages/typescript-config && cd packages/typescript-config
npm init -y
Enter fullscreen mode Exit fullscreen mode

2. Update the package.json with a proper name and export map:

{
  "name": "@dtr-cli/typescript-config",
  "version": "0.0.1",
  "description": "Shared Typescript configuration for @dtr-cli",
  "license": "ISC",
  "author": "Saiful Islam <[email protected]>",
  "exports": {
    "./base-tsconfig.json": "./base-tsconfig.json",
    "./backend-tsconfig.json": "./backend-tsconfig.json",
    "./react-tsconfig.json": "./react-tsconfig.json",
    "./vite-node-tsconfig.json": "./vite-node-tsconfig.json"
  },
  "files": [
    "base-tsconfig.json",
    "backend-tsconfig.json",
    "react-tsconfig.json",
    "vite-node-tsconfig.json"
  ],
  "devDependencies": {
    "@types/node": "^22.15.15"
  }
}
Enter fullscreen mode Exit fullscreen mode

3. Create Base and Extended Configs

Create these four config files inside your package:

base-tsconfig.json
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "display": "Base",
  "compilerOptions": {
    "strict": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
    "noUncheckedSideEffectImports": true,
    "esModuleInterop": true,
    "incremental": false,
    "sourceMap": false,
    "typeRoots": ["./node_modules/@types"]
  }
}
Enter fullscreen mode Exit fullscreen mode
react-tsconfig.json
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "extends": "./base-tsconfig.json",
  "display": "React Library",
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "isolatedModules": true,
    "moduleDetection": "force",
    "noEmit": true,
    "jsx": "react-jsx"
  }
}
Enter fullscreen mode Exit fullscreen mode
vite-node-tsconfig.json
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "extends": "./base-tsconfig.json",
  "display": "Vite Node",
  "compilerOptions": {
    "target": "ES2022",
    "lib": ["ES2023"],
    "module": "ESNext",
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "isolatedModules": true,
    "moduleDetection": "force",
    "noEmit": true
  }
}
Enter fullscreen mode Exit fullscreen mode

πŸ”Œ Installing the Config Package

To use your shared config package in any app inside your monorepo, add it to the app's package.json:

"devDependencies": {
  "@dtr-cli/typescript-config": "workspace:*"
}
Enter fullscreen mode Exit fullscreen mode

πŸ› οΈ How to Use the Configs

Backend App (apps/backend/tsconfig.json)
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "extends": "@dtr-cli/typescript-config/backend-tsconfig.json",
  "compilerOptions": {
    "rootDir": "./src",
    "outDir": "./dist",
    "typeRoots": ["./node_modules/@types", "./src/types"]
  },
  "include": ["./src/**/*.ts"],
  "exclude": ["node_modules", "dist"]
}
Enter fullscreen mode Exit fullscreen mode
Vite app (tsconfig.app.json)
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "extends": "@dtr-cli/tsconfig-config/react-tsconfig.json",
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    },
    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo"
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist", "test"]
}
Enter fullscreen mode Exit fullscreen mode
Vite app (tsconfig.node.json)
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "extends": "@dtr-cli/tsconfig-config/vite-node.json",
  "compilerOptions": {
    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo"
  },
  "include": ["vite.config.ts"]
}
Enter fullscreen mode Exit fullscreen mode
Vite app (tsconfig.json)
{
  "files": [],
  "references": [
    { "path": "./tsconfig.app.json" },
    { "path": "./tsconfig.node.json" }
  ],
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

βœ… Conclusion

By creating a reusable TypeScript config package in Turborepo, you:

  • Maintain consistency across all your apps.
  • DRY up repeated tsconfig.json logic.
  • Make onboarding and scaling much easier.

If you're managing a modern monorepo setup, especially using TypeScript, Turborepo, and pnpm, this strategy will pay off quickly. It’s a small step that brings a lot of organization and clarity to your developer experience.

Top comments (0)