TS5053Command Error
Since TS 1.6Updated in TS 1.6Updated in TS 1.7

Fix TS5053: Option Cannot Be Specified With Option

Learn why TypeScript throws TS5053 when two tsconfig options contradict each other, and how to fix the mutually exclusive pairs tsc rejects.

error TS5053: Option 'X' cannot be specified with option 'Y'

What This Error Means

TS5053 means you asked tsc to do two things at once that it cannot do together. Two compiler options arrived in the same program — from tsconfig.json, from an extends chain, from CLI flags, or from a mixture — and the pair describes contradictory behaviour. The compiler names both options and stops.

This check runs during option validation, before a single source file is parsed. Nothing about your types or your code is wrong: the program never got far enough to look at them. That is also why the error is reported against a line in tsconfig.json rather than against a .ts file, and why it often appears twice — once for each of the two options involved.

error TS5053: Option 'sourceMap' cannot be specified with option 'inlineSourceMap'.
                     ~~~~~~~~~~~                        ~~~~~~~~~~~~~~~~~
                     both set to true, and they mean different things

The pairs are mutually exclusive because each one is a fork in the emit pipeline: separate .map files or maps embedded in the JavaScript; write nothing or write only declarations; one bundled output or strictly file-by-file transpilation. TypeScript refuses to silently pick a winner, because whichever it picked would be wrong half the time.

Common Causes

1. Both Source-Map Modes Switched On

sourceMap writes a separate .js.map next to each output file. inlineSourceMap embeds the same data as a base64 comment inside the .js itself. You can have either, not both — usually this happens after merging a base config with a local one and not noticing that each contributed a different half.

// ❌ Broken — tsconfig.json
{
  "compilerOptions": {
    "strict": true,
    "outDir": "dist",
    "sourceMap": true,
    "inlineSourceMap": true
  },
  "include": ["src"]
}
[object Object]
// ✅ Fixed — pick the one that matches how you ship
{
  "compilerOptions": {
    "strict": true,
    "outDir": "dist",
    "inlineSourceMap": true
  },
  "include": ["src"]
}

Choose sourceMap when a bundler or a browser devtools setup fetches .map files separately — it keeps the shipped JavaScript small. Choose inlineSourceMap when the output travels alone and a sidecar file would get lost: a CLI published to npm, a serverless bundle, a Docker layer. Deleting the line you do not want is the whole fix; there is no setting that enables both.

2. A Build Config That Inherits noEmit From Its Base

This is the common one in real projects, and the reason is invisible until you look at the parent. The root tsconfig.json of an app set up by Vite, Next.js or Vue CLI usually carries "noEmit": true, because the bundler does the emitting. Add a tsconfig.build.json that extends it to produce .d.ts files for a published package, and the two settings collide.

// ❌ Broken — tsconfig.build.json
{
  "extends": "./tsconfig.base.json",
  "compilerOptions": {
    "declaration": true,
    "emitDeclarationOnly": true,
    "outDir": "dist"
  }
}
// tsconfig.base.json has "noEmit": true
error TS5053: Option 'emitDeclarationOnly' cannot be specified with option 'noEmit'.
// ✅ Fixed — turn the inherited option back off explicitly
{
  "extends": "./tsconfig.base.json",
  "compilerOptions": {
    "noEmit": false,
    "declaration": true,
    "emitDeclarationOnly": true,
    "outDir": "dist"
  }
}

extends merges compilerOptions key by key, so an option set in the base stays set until the child assigns it a new value. Writing "noEmit": false is not redundant — it is the only way to undo the inherited true.

The same collision arrives from the command line, because CLI flags are layered on top of the resolved config. A perfectly valid tsconfig.build.json fails the moment someone runs tsc -p tsconfig.build.json --noEmit out of habit:

[object Object]

If you want a type-check-only run against a config that emits declarations, drop the flag and use a separate config, or point tsc --noEmit at the root config instead.

3. outFile Together With isolatedModules

outFile concatenates the whole program into one output file, which requires the compiler to see every module at once and order them. isolatedModules promises the opposite: each file can be transpiled on its own, with no cross-file knowledge — the contract bundlers like esbuild and SWC rely on. The two cannot both hold.

// ❌ Broken — one bundle, but also "every file stands alone"
{
  "compilerOptions": {
    "strict": true,
    "module": "amd",
    "outFile": "dist/bundle.js",
    "isolatedModules": true
  },
  "include": ["src"]
}
[object Object]
// ✅ Fixed — let a bundler do the bundling, keep per-file emit
{
  "compilerOptions": {
    "strict": true,
    "module": "esnext",
    "outDir": "dist",
    "isolatedModules": true
  },
  "include": ["src"]
}

In almost every modern project outFile is the option to drop. It only works with the amd and system module formats, and the job it does — producing a single file — is done better by Vite, esbuild, Rollup or webpack, all of which want isolatedModules on anyway.

4. The Deprecated out Left Next To outFile

out is the TypeScript 1.x spelling of outFile, and it survives in old configs that someone half-modernised: the new key was added, the old one never removed.

// ❌ Broken — the same job, specified twice
{
  "compilerOptions": {
    "strict": true,
    "module": "amd",
    "out": "dist/legacy.js",
    "outFile": "dist/bundle.js"
  },
  "include": ["src"]
}
error TS5053: Option 'out' cannot be specified with option 'outFile'.
error TS5101: Option 'out' is deprecated and will stop functioning in TypeScript 5.5.
// ✅ Fixed — delete the legacy key
{
  "compilerOptions": {
    "strict": true,
    "module": "amd",
    "outFile": "dist/bundle.js"
  },
  "include": ["src"]
}

Note the second diagnostic. When TS5053 is accompanied by a deprecation warning such as TS5101, the deprecated option is the one to delete — that choice fixes both errors at once, and keeps the config working past TypeScript 5.5.

How to Fix It

  1. Read both option names in the message and decide which behaviour you want. TS5053 is unusually literal: it tells you exactly which two keys are fighting. Ask what each one does to the emit, pick the one that matches how the package is actually consumed, and delete the other. There is no merge, no precedence rule, and no flag that makes both apply.

  2. Follow the extends chain before touching anything. If you cannot find the second option in the file the error points at, it came from a base config — a shared @company/tsconfig package, a framework preset, a root config a monorepo child inherits. The fix belongs in the child, as an explicit override, not in the shared base that other packages depend on.

  3. Print the merged options with tsc --showConfig. Run tsc --showConfig -p tsconfig.build.json and you get the fully resolved compilerOptions that the compiler actually saw, extends already applied. Both offending keys will be in that output, which turns "where does this come from?" into a two-second question.

  4. Check the command line too, not just the files. Flags passed to tsc are layered on top of the resolved config, so tsc -p tsconfig.build.json --noEmit can produce TS5053 from a tsconfig.build.json that is perfectly valid on its own. If the error only appears through an npm script or in CI, read the script, not the config.

  5. Do not work around it by splitting the option across files. Moving one of the two keys into a config that extends the other changes nothing — the options are merged before validation, so the pair still arrives together. For genuinely different outputs, write genuinely separate configs (tsconfig.json for the editor and type-checking, tsconfig.build.json for emit) that each set the full picture, and give each one its own npm script so nobody has to remember which flags to add.

FAQ

What causes TypeScript error TS5053?

The compiler validates its options before it parses any code, and a small set of option pairs is rejected outright because the two settings describe contradictory emit behaviour. sourceMap and inlineSourceMap are two different places to put the same data; noEmit and emitDeclarationOnly disagree about whether to write files at all; outFile and isolatedModules disagree about whether the compiler may look across files. Since every one of those conflicts has two defensible resolutions, TypeScript refuses to choose for you and reports TS5053 instead. The error is pure configuration — your source files are untouched and uninspected.

Which tsconfig options are mutually exclusive?

The pairs you will realistically meet are sourceMap with inlineSourceMap, noEmit with emitDeclarationOnly, outFile with isolatedModules, and the deprecated out with outFile. There are others, and the exact set shifts between releases — combinations that were rejected years ago are legal now, including noEmit with incremental (allowed since TypeScript 4.0) and declaration with allowJs (allowed since 3.7). So do not work from a memorised list: the two names in your particular message are the authoritative answer, and a related but distinct diagnostic, TS5069, covers the opposite situation where one option requires another.

How do I override an inherited option from an extended tsconfig?

Assign the option again in the child config with the value you want — including false, which is the case people miss. extends performs a shallow merge over compilerOptions, so a key set in the base survives into the child until the child sets it to something else; there is no "unset" syntax and deleting the key from the child does nothing. A build config extending a root that has "noEmit": true therefore needs a literal "noEmit": false line before emitDeclarationOnly will be accepted. To confirm it worked, run tsc --showConfig -p tsconfig.build.json and read the resolved options the compiler will use.

Related Errors

Practice This

Browse all TypeScript practice challenges to keep sharpening your type-level skills.

Share this reference

Become a TypeScript Pro

Track your progress through 200+ hands-on challenges. Free, sign in with GitHub.

Or start solving right away: explore all TypeScript challenges