Generate a tsconfig.json that fits your project
tsconfig.json controls how the TypeScript compiler interprets and emits your
code. The right settings differ sharply between a Node service, a React app
compiled by a bundler, and a library you publish to npm. This builder asks what
you are building and produces a sensible, modern configuration with the correct
target, module, moduleResolution, strictness flags, and output options.
How it works
The output is a single compilerOptions object plus include/exclude arrays.
The builder selects defaults by project type:
- Node app —
module: "nodenext",moduleResolution: "nodenext", emit enabled tooutDir. - React / bundler —
module: "esnext",moduleResolution: "bundler",jsx: "react-jsx", andnoEmit: truebecause the bundler emits. - Library — emit enabled with
declaration: trueanddeclarationMap: trueso consumers get type definitions and go-to-definition.
Strictness layers on top. A typical strict config looks like:
{
"compilerOptions": {
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
}
}
Path aliases are written as a baseUrl plus a paths map. Remember the aliases
must also be configured in your runtime or bundler — tsconfig only teaches the
type-checker about them.
Key settings by project type
Node.js application or API
Use "module": "nodenext" and "moduleResolution": "nodenext" to match how Node’s native ESM loader resolves imports. This requires .js extensions on relative imports (even in .ts files), which surprises developers coming from bundler projects.
{
"compilerOptions": {
"target": "es2022",
"module": "nodenext",
"moduleResolution": "nodenext",
"outDir": "./dist",
"strict": true
}
}
React or Vite / Next.js application
The bundler handles output; TypeScript only needs to type-check. Setting noEmit: true makes that explicit and prevents accidental dual-compilation:
{
"compilerOptions": {
"target": "es2020",
"module": "esnext",
"moduleResolution": "bundler",
"jsx": "react-jsx",
"noEmit": true,
"strict": true
}
}
Published npm library
Consumers of your library need .d.ts type-definition files. Emit JavaScript and declarations together:
{
"compilerOptions": {
"target": "es2020",
"module": "esnext",
"moduleResolution": "bundler",
"declaration": true,
"declarationMap": true,
"outDir": "./dist",
"strict": true
}
}
declarationMap adds source-map support so a user’s IDE “Go to definition” jumps to your original .ts source rather than the compiled .d.ts.
Tips and notes
- Start strict, loosen later —
strict: trueenables a family of checks at once. Retrofitting strictness onto a large untyped codebase is painful; start strict from day one. skipLibCheck: truespeeds builds significantly by trusting third-party.d.tsfiles. It hides real bugs in those files, but almost every real project uses it.noUncheckedIndexedAccessis not part ofstrictbut is highly recommended: accessingarray[i]returnsT | undefinedrather thanT, catching a real class of bugs.- Path aliases need both sides configured —
tsconfigpaths teach only the type-checker. Your bundler (Viteresolve.alias, webpackresolve.alias, Node--experimental-specifier-resolution) must be configured separately with matching rules. targetvslib—targetcontrols which JS syntax is emitted;libcontrols which type declarations are available. They are independent. Atarget: "es5"project can still uselib: ["es2022"]if it polyfills at runtime.