include / exclude / files
Selects which source files enter the program, using globs, an allowlist, or a skip list.
{
"files": string[],
"include": string[],
"exclude": string[]
}- Added in TypeScript 1.5
Parameters
| Parameter | Type | Description |
|---|---|---|
$filesoptional | string[]= false | An allowlist of exact file paths to include in the program. An error occurs if any of them cannot be found. Use it for a handful of files; use include when you need globs. Released in 1.5. |
$includeoptional | string[]= [] if files is specified; **/* otherwise | Filenames or glob patterns to include, resolved relative to the directory containing the tsconfig.json. `*` matches zero or more characters except a directory separator, `?` matches one such character, and `**/` matches any directory nested to any level. A last segment with no extension and no wildcard is treated as a directory. Released in 2.0. |
$excludeoptional | string[]= node_modules, bower_components, jspm_packages, and outDir | Filenames or patterns skipped when resolving include. It filters include only — it does not prevent a file from entering the program. Released in 2.0. |
Errors
A path listed in `files` that does not exist is an error. A config whose include/files pattern matches nothing raises TS18003, "No inputs were found in config file".
Changelog
- PHP 2.0include and exclude added. Before this, a config either listed every file explicitly or compiled the whole directory.
These three settings choose the program's roots. Everything reachable from a root by an import, a types entry or a /// <reference> is pulled in on top, whether or not you named it.
Why exclude does not exclude
This is the single most reported non-bug. exclude filters what include finds — nothing more. A file under exclude still becomes part of the codebase if something imports it, if it is named in files, or if a reference directive points at it. It is not a mechanism that prevents a file from being compiled; delete the import, or move the file outside the project, if you truly want it gone.
The same asymmetry explains why node_modules types still get checked despite the default exclude: your code imports them.
Choosing between them
Reach for include for essentially every real project — ["src/**/*"] plus an exclude for tests or build output. Reach for files only for a small fixed list where a missing file should be a hard error, since files is checked, not globbed.
Glob details worth knowing
A pattern segment with no extension and no wildcard means a directory, and picks up .ts, .tsx and .d.ts — plus .js and .jsx when allowJs is on. And remember that when a config extends another, declaring any of these three replaces the base's version outright.
Example
// tsconfig.json
// { "include": ["src/**/*"], "exclude": ["src/legacy"] }
// src/legacy/money.ts — matched by exclude, compiled anyway
export const money = (cents: number) => `$${(cents / 100).toFixed(2)}`;
// src/checkout.ts — an include root, and it imports the "excluded" file
import { money } from "./legacy/money";
console.log("total:", money(4250)); // total: $42.50
// tsc pulls src/legacy/money.ts into the program through the import.
// exclude removed it from the include glob; the import put it straight back.When to use it
- Compile only src/ while keeping fixtures and build output out of the program
- Split a tsconfig.build.json that excludes *.test.ts from the editor config that includes them
- Pin a tiny declaration-only project to an exact file list so a missing file fails the build
Frequently asked questions
Why is TypeScript still compiling a file I put in exclude?
Because something imports it. exclude only filters the files that include would have matched; an import, a files entry, or a /// <reference> pulls the file back into the program regardless.
What is the difference between files and include?
files is an exact allowlist that errors when a listed path is missing, while include takes glob patterns and silently matches whatever exists — use files for a small fixed set, include for everything else.
What does tsc compile if I specify neither include nor files?
Everything: include defaults to **/* from the tsconfig.json's directory, minus the default exclude of node_modules, bower_components, jspm_packages and outDir.
More examples
files: an exact allowlist
The sorted join prints `solo:1 team:10` on every run. The interesting part is the config: with `files`, a path that no longer exists stops the build with TS6053 instead of quietly compiling a smaller program, which is what makes it worth using for small, deliberately fixed file sets.
// tsconfig.json
// {
// "files": ["src/index.ts", "src/types.ts"],
// "compilerOptions": { "declaration": true, "outDir": "dist" }
// }
// A typo here — "src/typez.ts" — fails the build immediately:
// error TS6053: File 'src/typez.ts' not found.
interface Plan { name: string; seats: number }
const plans: Plan[] = [
{ name: "team", seats: 10 },
{ name: "solo", seats: 1 },
];
console.log(plans.map(p => `${p.name}:${p.seats}`).sort().join(" "));
// solo:1 team:10Two configs over one source tree
The log shows the file set the build config resolves to: only `src/cart.ts`. Note that tsconfig.build.json restates `include` even though it extends the editor config — include, exclude and files overwrite rather than merge, so the inherited `tests/**/*` would otherwise still be there, and the local `exclude` would not remove it.
// tsconfig.json — what the editor sees
// { "include": ["src/**/*", "tests/**/*"] }
//
// tsconfig.build.json — what ships
// { "extends": "./tsconfig.json",
// "include": ["src/**/*"],
// "exclude": ["src/**/*.test.ts", "src/**/__fixtures__"] }
const files = [
"src/cart.ts",
"src/cart.test.ts",
"tests/e2e.ts",
];
const shipped = files.filter(f => f.startsWith("src/") && !f.endsWith(".test.ts"));
console.log("build program:", shipped.join(", "));
// build program: src/cart.ts
Discussion