/flags/typescript/tsc-outdir-rootdir
tsc --outDir and --rootDir: control where compiled .js files go
- tool
- TypeScript
- command
- tsc
- flag
- --outDir <dir>, --rootDir <dir>
- default
- outDir: none (each .js is written next to its .ts); rootDir: the folder of tsconfig.json in TypeScript 6+
--outDir dist makes tsc write the compiled .js (and .d.ts, .map) files into dist instead of next to each .ts file. --rootDir src says which source folder that output tree starts from, so src/index.ts becomes dist/index.js rather than dist/src/index.js. Every compiled file must live under rootDir; a file outside it fails with TS6059 "'rootDir' is expected to contain all source files".
The three common situations
npm init -y >/dev/null
npm install --silent --no-audit --no-fund typescript@7.0.2 >/dev/null 2>&1
mkdir -p src scripts
echo 'export const a: number = 1;' > src/index.ts
echo 'console.log("build helper");' > scripts/build.ts
opts='"module": "nodenext", "target": "es2022", "strict": true, "types": []'
echo "== 1. outDir only, include src"
echo "{ \"compilerOptions\": { \"outDir\": \"dist\", $opts }, \"include\": [\"src\"] }" > tsconfig.json
npx tsc; echo "exit: $?"; find dist -type f; rm -rf dist
echo "== 2. outDir + rootDir src, include src"
echo "{ \"compilerOptions\": { \"outDir\": \"dist\", \"rootDir\": \"src\", $opts }, \"include\": [\"src\"] }" > tsconfig.json
npx tsc; echo "exit: $?"; find dist -type f; rm -rf dist
echo "== 3. rootDir src, but scripts/ is included too"
echo "{ \"compilerOptions\": { \"outDir\": \"dist\", \"rootDir\": \"src\", $opts } }" > tsconfig.json
npx tsc; echo "exit: $?"Output
== 1. outDir only, include src
tsconfig.json(1,24): error TS5011: The common source directory of 'tsconfig.json' is './src'. The 'rootDir' setting must be explicitly set to this or another path to adjust your output's file layout.
Visit https://aka.ms/ts6 for migration information.
exit: 2
dist/src/index.js
== 2. outDir + rootDir src, include src
exit: 0
dist/index.js
== 3. rootDir src, but scripts/ is included too
error TS6059: File '/tmp/work/scripts/build.ts' is not under 'rootDir' '/tmp/work/src'. 'rootDir' is expected to contain all source files.
The file is in the program because:
Matched by default include pattern '**/*'
File is CommonJS module because '/tmp/work/package.json' has field "type" whose value is not "module"
exit: 2- Without
rootDir, TypeScript 7 uses the folder oftsconfig.jsonas the root, writesdist/src/index.jsand exits with status 2, reporting TS5011 because the common source folder (./src) differs from it. Older versions silently used the common source folder and wrotedist/index.js, so this is a frequent upgrade surprise. - With
rootDir: "src"the layout is flat and there is no error. - Without
include, every.tsin the project is compiled,scripts/build.tsis outsidesrc, and tsc stops with TS6059, explaining that the file came from the default include pattern**/*.
How the options interact
| Option | Effect | Default |
|---|---|---|
| outDir | Folder for emitted .js, .d.ts and .map files | none: files are emitted next to the sources |
| rootDir | Base folder whose structure is reproduced under outDir | TypeScript 6+: folder of the tsconfig; before: longest common folder of the inputs |
| include / exclude / files | Which files are compiled | include: **/* in the tsconfig folder |
| declarationDir | Separate folder for .d.ts files | same as outDir |
| noEmit | Type check only, write nothing | false |
Fixing TS6059 and TS5011
- TS6059 (file is not under rootDir): either narrow
includeto the source folder ("include": ["src"]), move the file intosrc, or widenrootDir(for example to.) and accept a nested output layout. Test files and config scripts such asvite.config.tsare the usual intruders; give them their own tsconfig withnoEmit. - TS5011 (common source directory differs): set
rootDirexplicitly to the folder the message names, usually./src. The message links to the TypeScript 6 migration notes. - Imports from outside rootDir: a relative import of
../shared/util.tspulls that file into the program, and it then has to be insiderootDirtoo. Use project references or a package for shared code.
Pitfalls
outDirdoes not clean old output. Renamed or deleted sources leave stale.jsfiles indist; delete the folder in your build script before compiling.- Paths in an extended config are resolved from that config's folder: a base config in
configs/with"outDir": "dist"writes toconfigs/dist. See tsc -p and check the result with tsc --showConfig. - Without
outDir,.jsfiles appear next to the.tssources and can be picked up by the next compile or by your test runner.
FAQ
Why does tsc put my files in dist/src instead of dist?
The output mirrors the source tree relative to rootDir. If rootDir is the project folder (the default in TypeScript 6 and 7), src/index.ts is written to dist/src/index.js. Set rootDir to src to get dist/index.js.
Does rootDir decide which files are compiled?
No. include, files and imports decide that. rootDir only says which folder the output layout starts from, and every compiled file must be inside it, otherwise tsc reports TS6059.
Where do .d.ts files go?
With declaration enabled they go next to the .js files in outDir, unless declarationDir sets another folder. Both follow the same rootDir layout.