C.W.K.
Stream
Lesson 05 of 05 · published

`tsconfig.json` Deep Dive

~9 min · tooling, tsconfig, configuration

Level 0Curious
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete
"tsconfig has 100+ options. Ten of them matter most of the time."

The options that matter most

  • target — JavaScript version to emit. ES2022 is the modern default; older targets transpile syntax down. Match your runtime.
  • module — module system to emit. NodeNext for Node ESM, ESNext for bundlers, CommonJS only for legacy Node.
  • moduleResolution — how imports get resolved. NodeNext for modern Node, Bundler for Vite/esbuild.
  • strict — the safety meta-flag. Always true. Covered in detail in the next track.
  • esModuleInterop — makes CommonJS interop saner. Set to true.
  • skipLibCheck — skip type checks on .d.ts files. true for most projects (faster, and you can't fix library types anyway).
  • forceConsistentCasingInFileNames — catch case mismatches in imports (./MyFile vs ./myfile). Always true.
  • outDir — where compiled JS goes (only matters if you emit).
  • rootDir — where source TS comes from. Pairs with outDir.
  • include / exclude — file patterns. include: ['src'] is typical; exclude usually defaults to node_modules + dist.

tsconfig bases

The @tsconfig/* packages on npm provide pre-tuned tsconfig bases for common scenarios. extends: "@tsconfig/node20" inherits the right defaults for Node 20. Use these — they cover the boring parts and let you focus on your project's specifics.

Start with a known-good base, override only what you must. Hand-tuning every option of a fresh tsconfig is a waste; the community has converged on sensible defaults. Use them.

Code

Two tsconfigs — explicit and inherited·json
// tsconfig.json — sensible 2026 defaults for a Node ESM project.
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,

    "verbatimModuleSyntax": true,
    "noUncheckedIndexedAccess": true,

    "outDir": "./dist",
    "rootDir": "./src"
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

// Extending a base:
{
  "extends": "@tsconfig/node20/tsconfig.json",
  "compilerOptions": {
    "outDir": "./dist"
  },
  "include": ["src/**/*"]
}

External links

Exercise

Take a fresh project's tsconfig.json. Replace its compilerOptions with extends: "@tsconfig/node20". Run tsc --noEmit and see what (if anything) breaks. The breakages are usually the strict flags catching latent issues.
Hint
If everything still compiles, your project was already strict. If breakages appear, the base is doing its job — catching gaps your old config missed.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.