tsconfig.json Key Options
| Since: | TypeScript 1.0(2014) |
|---|
tsconfig.json is the configuration file that controls how the TypeScript compiler behaves. Placing it in the project root lets you configure the scope of files to compile, the output format for transpilation, and the strictness of type checking — all in one place.
Syntax
// tsconfig.json (JSON format)
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"strict": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
Main Options
| Option | Description |
|---|---|
| target | Specifies the JavaScript version to output (ES5, ES2020, ESNext, etc.). |
| module | Specifies the module format (CommonJS, ESNext, NodeNext, etc.). |
| lib | Specifies the built-in type definitions to use (DOM, ES2020, etc.). Inferred from target if omitted. |
| strict | Enables all strict type-checking options at once. Recommended to set to true for new projects. |
| outDir | Specifies the directory where compiled files are written. |
| rootDir | Specifies the root directory of source files. |
| paths | Configures module resolution aliases. Requires baseUrl to be set. |
| baseUrl | Specifies the base directory for module resolution. |
| declaration | When set to true, automatically generates .d.ts declaration files. |
| sourceMap | When set to true, generates source map files (useful for debugging). |
| noEmit | When set to true, performs type checking only without emitting JS files. |
| esModuleInterop | Allows CommonJS modules to be imported using ES module syntax. |
| moduleResolution | Specifies the module resolution strategy (node, bundler, etc.). |
| include | Glob patterns for files and directories to include in compilation. |
| exclude | Glob patterns for files and directories to exclude from compilation. |
| extends | Inherits configuration from another tsconfig.json. |
Sample Code
// tsconfig.json for a typical web app
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "bundler",
"lib": ["ES2020", "DOM"],
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"skipLibCheck": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
// tsconfig.json for Node.js (server-side)
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"outDir": "dist",
"rootDir": "src",
"declaration": true,
"sourceMap": true,
"strict": true
},
"include": ["src/**/*"]
}
Notes
target specifies the JavaScript version to output, and module specifies the module format. When using a browser-side bundler, moduleResolution: "bundler" (TypeScript 5.0+) is recommended. For Node.js, use module: "NodeNext" together with moduleResolution: "NodeNext".
For strict type-checking options, see strict mode options.
paths (Path Aliases)
paths is used together with baseUrl to define import path shortcuts (aliases). As project folder hierarchies grow deeper, relative paths become long and hard to read.
import { db } from "../../../config/database";
import { logger } from "../../../lib/logger";
// With paths (@ acts as a shortcut)
import { db } from "@/config/database";
import { logger } from "@/lib/logger";
Configuration
Set baseUrl and paths in tsconfig.json.
tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}
With this configuration, @/config/database resolves to ./src/config/database. baseUrl sets the base directory for path resolution — "." refers to the project root (the folder containing tsconfig.json).
Caution: Path resolution after compilation
paths works correctly for TypeScript's type checking and editor autocompletion, but the compiled .js files do not automatically rewrite @/ to actual paths.
// TypeScript source (.ts)
import { db } from "@/config/database";
The same logic can also be written as:
// Compiled .js by tsc (@/ remains as-is)
const database_1 = require("@/config/database"); // Node.js cannot resolve this
You need a separate mechanism to resolve paths at runtime. Here are the main approaches — choose one that matches your project's runtime environment. Using multiple approaches at the same time can cause paths to be resolved twice, leading to unexpected errors.
| Approach | How it works | Use case |
|---|---|---|
| tsc-alias | Scans compiled .js files and replaces @/ with relative paths. | Projects that run directly on Node.js |
| tsconfig-paths | Hooks into Node.js require() to resolve paths at runtime. | Development with ts-node |
| Bundler configuration | Configure aliases in Vite (resolve.alias) or webpack (resolve.alias). | Browser-based applications |
Using tsc-alias
This tool scans compiled .js files and replaces @/ with relative paths. It is suited for projects that run directly on Node.js.
npm install --save-dev tsc-alias
Add tsc-alias to the build script in package.json. The order matters — it must run after tsc.
package.json
{
"scripts": {
"build": "tsc && tsc-alias",
"build:watch": "concurrently \"tsc --watch\" \"tsc-alias --watch\""
}
}
Running tsc-alias on the compiled .js files rewrites @/config/database to relative paths like ./config/database. The --watch option monitors file changes and rewrites automatically.
Using tsconfig-paths
This tool hooks into Node.js require() to resolve paths at runtime. It does not modify .js files — paths are resolved dynamically. It is suited for development with ts-node.
npm install --save-dev tsconfig-paths
To use it with ts-node, add the following to tsconfig.json.
tsconfig.json
{
"ts-node": {
"require": ["tsconfig-paths/register"]
}
}
With this configuration, @/ is automatically resolved when running with ts-node.
ts-node src/index.ts
To run compiled .js files with node, register it with the -r option.
node -r tsconfig-paths/register dist/index.js
Using Vite (bundler)
When using a bundler like Vite or webpack, you need to configure aliases on the bundler side as well. Since the bundler resolves paths during the bundling stage, tsc-alias and tsconfig-paths are not needed.
npm install --save-dev vite
Add the following alias configuration to vite.config.ts.
vite.config.ts
import { defineConfig } from "vite";
import path from "path";
export default defineConfig({
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
});
For webpack, configure it in resolve.alias of webpack.config.js.
webpack.config.js
const path = require("path");
module.exports = {
resolve: {
alias: {
"@": path.resolve(__dirname, "src"),
},
},
};
paths is a convenient feature, but since the TypeScript compiler itself does not resolve paths in the compiled output, additional configuration is required depending on your runtime environment.
If you find any errors or copyright issues, please contact us.