Learn why TypeScript throws TS6307 when a composite project imports a file its files or include list never declared, and how to fix the tsconfig.
TS6307 means an import pulled a file into the program that your tsconfig.json never declared. TypeScript found the file, read it fine, and then refused to compile the import — because in a composite project, the file list is a contract, and this file is not on it.
Composite projects exist so that tsc -b can be fast and so that other projects can consume your build. To decide whether your project is up to date, the build mode needs to know every input before it parses anything, and a referencing project needs to know which .d.ts files will exist. Both guarantees collapse if the file list can grow by following imports at type-check time. So when composite: true is set, every file in the program must be matched by files or include, and a file that entered only because something imported it is an error.
That is also why this error is invisible in most projects. Drop composite from the same tsconfig.json and the identical import compiles without a word — the compiler happily follows imports outward when it does not owe anyone a file list. The flags that matter here are composite, files and include; nothing about your types is wrong.
error TS6307: File '/app/src/formatMoney.ts' is not listed within the file list
of project '/app/tsconfig.json'. Projects must list all files or
use an 'include' pattern.
~~~~~~~~~~~~~~~~~~~~
read by the compiler, but never declared in tsconfig.jsonThe message names two paths: the file that is missing from the list, and the config file whose list is missing it. The fix always lands in the second one.
If you are reading an older thread, TypeScript 2.9 through 3.5 worded this as "File 'X' is not in project file list. Projects must list all files or use an 'include' pattern." It is the same diagnostic — the text was rewritten in 3.6.
files List That Forgot A Dependencyfiles is an exact list, not a starting point. Naming only your entry point works right up until that entry point imports something.
// ❌ Broken — tsconfig.json
{
"compilerOptions": {
"composite": true,
"outDir": "dist",
"rootDir": "src",
"strict": true
},
"files": ["src/index.ts"]
}// src/index.ts
import { formatMoney } from "./formatMoney"
// ~~~~~~~~~~~~~~
// Error: File '/app/src/formatMoney.ts' is not listed within the file list of
// project '/app/tsconfig.json'. Projects must list all files or use an
// 'include' pattern.
export const orderTotal = formatMoney(1999)// ✅ Fixed — let a directory include describe the whole source tree
{
"compilerOptions": {
"composite": true,
"outDir": "dist",
"rootDir": "src",
"strict": true
},
"include": ["src"]
}Reach for files only when the list is genuinely fixed and short — a single ambient .d.ts, a one-file build script. For application code, include is the maintainable answer: it keeps working when someone adds a module tomorrow.
resolveJsonModule makes import cfg from "./config.json" resolve. It does not add the file to your file list, and src/**/*.ts does not match .json. Neither, and this surprises people, does a bare directory include like "src" — directory expansion covers TypeScript and JavaScript extensions, not JSON.
// ❌ Broken — the glob only ever matches .ts
{
"compilerOptions": {
"composite": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"outDir": "dist",
"rootDir": "src",
"strict": true
},
"include": ["src/**/*.ts"]
}// src/index.ts
import featureFlags from "./featureFlags.json"
// ~~~~~~~~~~~~~~~~~~~~
// Error: File '/app/src/featureFlags.json' is not listed within the file list
// of project '/app/tsconfig.json'.
export const checkoutEnabled: boolean = featureFlags.checkout// ✅ Fixed — say the quiet part explicitly
{
"compilerOptions": {
"composite": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"outDir": "dist",
"rootDir": "src",
"strict": true
},
"include": ["src/**/*.ts", "src/**/*.json"]
}Naming the file in files works too, but the glob scales. The same trap catches any non-code asset you import for its type — a .json locale bundle, a generated schema — so add the pattern once, at the top of the project.
includeThe project compiles src, and one day src/api.ts reaches into a shared/ folder next door. Without composite this just works; with it, shared/ has to be declared.
// ❌ Broken — "shared" was never part of the project
{
"compilerOptions": { "composite": true, "outDir": "dist", "strict": true },
"include": ["src"]
}// src/api.ts
import type { OrderStatus } from "../shared/orderStatus"
// ~~~~~~~~~~~~~~~~~~~~~~
// Error: File '/app/shared/orderStatus.ts' is not listed within the file list
// of project '/app/tsconfig.json'.
export function isSettled(status: OrderStatus): boolean {
return status === "paid"
}// ✅ Fixed — the project is both folders, so say so
{
"compilerOptions": { "composite": true, "outDir": "dist", "strict": true },
"include": ["src", "shared"]
}Note that import type does not save you: a type-only import still brings the file into the program, and the file list check does not care that nothing is emitted for it. If shared/ is meant to be its own unit with its own build output, make it a referenced project instead — that is cause 4.
In a workspace, the tempting shortcut is to reach across into the other package's src/. Every composite package that does this reports TS6307, usually next to TS6059 complaining about rootDir — two symptoms of the same mistake.
// packages/web/src/cart.ts
// ❌ Broken — reaching into another package's sources
import { formatMoney } from "../../core/src/index"
// ~~~~~~~~~~~~~~~~~~~~
// Error TS6059: File '/app/packages/core/src/index.ts' is not under 'rootDir'
// '/app/packages/web/src'.
// Error TS6307: File '/app/packages/core/src/index.ts' is not listed within the
// file list of project '/app/packages/web/tsconfig.json'.
export const cartLabel = formatMoney(4250)// ✅ Fixed — packages/web/tsconfig.json declares the dependency
{
"compilerOptions": {
"composite": true,
"outDir": "dist",
"rootDir": "src",
"strict": true
},
"include": ["src"],
"references": [{ "path": "../core" }]
}// packages/web/src/cart.ts
// ✅ Fixed — import the package, not the file
import { formatMoney } from "@acme/core"
export const cartLabel = formatMoney(4250)With the reference in place, tsc -b packages/web builds core first and resolves @acme/core to its emitted dist/index.d.ts. The other package's sources never join your program, so there is nothing left to list. This is also the shape that Nx, Turborepo and tsc -b all expect, which is why the relative-path shortcut tends to break tooling long before it breaks type checking.
Widen include to cover the file the message names. Prefer directory entries ("src", "shared") over extension globs ("src/**/*.ts"): a directory keeps matching when someone adds a .tsx or a .mts, a hand-written glob does not. This single change fixes the large majority of TS6307 reports.
Add an explicit pattern for non-TypeScript inputs. JSON is the common one — "include": ["src", "src/**/*.json"] — because resolveJsonModule changes resolution but never the file list. Anything you import that is not .ts/.tsx/.js needs to be named, by glob or in files.
Declare cross-package dependencies as project references. Add "references": [{ "path": "../core" }] and import by package name rather than by relative path into the other package's src. Build with tsc -b, which resolves the graph, builds dependencies first and points the import at their .d.ts output. This is the fix that also makes TS6059 and stale-build errors go away.
Use files only for genuinely fixed lists, and keep it complete. A files array that names one entry point is a bug waiting to happen in a composite project; either list everything or switch to include.
Remove composite if — and only if — nothing depends on it. If no other project references this one and you never run tsc -b, composite: true buys you nothing and the file-list contract goes with it. Do not do this to a package that sits in a reference graph: you will trade one honest error for slow rebuilds and missing declaration output. And if the config already looks correct but your editor still underlines the import, restart the TypeScript server — tsserver has a long history of caching a stale file list here, while tsc -p tsconfig.json on the command line tells you the truth.
TS6307 is exclusive to projects with composite: true. A composite project promises that its complete set of input files can be computed from tsconfig.json alone, with no import resolution — that is what lets tsc -b decide up-to-date-ness cheaply and lets referencing projects know which .d.ts files to expect. When an import resolves to a file that neither files nor include matches, that promise is broken, so the compiler reports TS6307 at the import instead of silently growing the program. Delete composite from the same config and the identical code compiles, which is the quickest way to confirm the diagnosis.
resolveJsonModule and the file list are two separate mechanisms. The flag teaches module resolution to accept ./featureFlags.json and infer a type from its contents; it does not touch include. A pattern such as src/**/*.ts obviously does not match .json, and a bare "src" directory entry does not either — directory expansion covers the supported TypeScript and JavaScript extensions only. Add "src/**/*.json" to include, or list the specific file in files:
{
"include": ["src", "src/**/*.json"]
}Ask whether anything references this project. composite is required for a project that appears in another project's references array, and it is what tsc -b uses to skip work that is already up to date; it also forces declaration: true so consumers get .d.ts files. If your project is a leaf that nobody references and you build it with a plain tsc -p tsconfig.json — or with Vite, esbuild or SWC, with tsc only doing --noEmit type checks — then composite is ceremony and dropping it is a legitimate fix. If you are in a monorepo with a reference graph, keep it and fix include instead; the flag is the reason the graph builds incrementally at all.
Browse all TypeScript practice challenges to keep sharpening your type-level skills.
Track your progress through 100+ hands-on challenges. Free, sign in with GitHub.
Or start solving right away: explore all TypeScript challenges