Skip to content
Quasar Tools Logo

TypeScript TS1384 Error Explained and Fixed

TypeScript TS1384 error explained: what it means, why it fires, and every fix — module augmentation, isolatedModules, declare global, and tsconfig settings.

DH
Tutorials & How-Tos11 min read2,650 words

TypeScript TS1384 is one of those errors that looks cryptic on first encounter but has a precise, fixable cause every time. It fires when the compiler finds an export modifier somewhere it cannot legally appear — specifically inside a module augmentation block. This guide explains exactly what TS1384 means, walks through every scenario that triggers it, and gives you the correct fix for each one.

TS1384Error codeModule augmentation export
1 lineTypical fixexport {} resolves most cases
3Root causesScript, isolatedModules, .d.ts

What is TS1384?

TypeScript error TS1384 carries the message: "'export' modifier cannot be applied to a module augmentation." It fires when the compiler encounters an `export` keyword inside a `declare module` or `declare global` block — the two constructs TypeScript uses for module augmentation. Augmentation blocks are for extending the types of existing modules, not for declaring new public symbols, so export is structurally invalid inside them.

Module augmentation in one sentence

Module augmentation is the TypeScript mechanism that lets you add new members to an existing module's types — for example, adding a custom property to `Express.Request`, extending `Window` with a third-party global, or adding methods to a framework's component options. The syntax looks like a `declare module 'module-name' ` block, and it must live inside a module file (a file with at least one top-level `import` or `export` statement).

  • TS1384 is a compiler error — the file will not type-check until it is fixed
  • It does not affect runtime — the error is purely about type declarations
  • It is deterministic — the same code always triggers it; there is no intermittent version
  • It has a small set of root causes — script vs module context, isolatedModules, and incorrect .d.ts structure cover 95% of cases

Note

TS1384 is related to but distinct from TS2669 ("Augmentations for the global scope can only be directly nested in external modules or ambient module declarations"). Both stem from wrong file context for augmentation syntax, and both are fixed by the same `export ` technique — but TS2669 fires on the `declare global` block location, while TS1384 fires specifically on an `export` modifier inside the augmentation.

When TS1384 fires

The error always involves an `export` in a place where TypeScript does not allow one. There are three distinct patterns that produce it, and identifying which one applies to your codebase determines the correct fix.

Pattern 1 — export inside a declare module block

The most direct trigger: you write an `export` statement inside a `declare module` augmentation. The intent is usually to add something to the module's public API, but augmentation blocks do not work that way — they can only extend type declarations that already exist in the target module.

typescript
// ✗ TS1384 — export inside module augmentation
declare module 'some-library' {
  export interface NewInterface {   // <-- TS1384 fires here
    id: string;
  }
}

// ✓ Correct — interface added without export
declare module 'some-library' {
  interface ExistingInterface {
    newProperty: string;            // extends the existing type
  }
}

Pattern 2 — file treated as a script, not a module

This is the most common cause of TS1384 in real projects. If a file has no top-level `import` or `export` statements, TypeScript treats it as a script with global scope. A `declare global ` block in a script file is meaningless — globals are already global in script files — so TypeScript rejects any `export` inside it with TS1384. The file needs to be a module for the augmentation context to make sense.

Pattern 3 — incorrect .d.ts file structure

Declaration files (`.d.ts`) that mix ambient module declarations with regular export statements in the wrong order can trigger TS1384. A `.d.ts` file that starts with top-level `export` declarations and then contains a `declare module` block is treated as a module, which is correct. But a `.d.ts` that wraps everything inside a single `declare module` block and then tries to use `export` inside that block confuses the augmentation context with a module definition context.

Warning

TS1384 can also originate from a **third-party package** that ships broken `.d.ts` files. If the error points to a path inside `node_modules`, the source is a dependency — not your code. The fix in that case is `skipLibCheck: true` in tsconfig.json, not modifying the package files.

How to fix TS1384: module augmentation

The right fix depends on what you are actually trying to accomplish. There are two different goals that can lead to TS1384, and they require different approaches. Work through these four steps to resolve the error cleanly.

1

Identify which pattern is triggering TS1384

Read the full compiler error carefully. Note the file extension (.ts vs .d.ts), the line number, and whether the `export` is inside a `declare module` block, a `declare global` block, or somewhere else. The surrounding code context tells you which of the three patterns above applies. If the error path starts with `node_modules/`, skip to the `skipLibCheck` fix — the other patterns do not apply.

2

Add export {} to convert the file to a module

If your file has a `declare module` or `declare global` block but no top-level imports or exports, add `export ` at the top. This single line converts the file from script context to module context, which is the required environment for augmentation syntax. The empty export does not add anything to the compiled output — it is purely a TypeScript context signal.

src/types/global.d.ts
typescript
// Add this line to convert the file to a module
export {};

declare global {
  interface Window {
    myAnalytics: AnalyticsInstance;
  }
}
3

Move declare global into an existing module

An alternative to adding `export ` is placing the `declare global` block inside a file that already has real imports or exports — such as the entry point of a library, a feature module, or a shared utilities file. This approach keeps your type augmentations co-located with the code they extend, which can be easier to maintain than a dedicated global declarations file.

4

Remove export from inside the augmentation block

If you genuinely want to add a new exportable type to an existing module's public API, the augmentation block is the wrong place for it. Move the declaration outside the `declare module` block entirely. To augment an existing interface, use the same interface name without `export` inside the block — TypeScript merges it automatically via declaration merging.

JSON Formatter & Validator

Validate your tsconfig.json and package.json for syntax errors instantly in your browser — no TypeScript compiler required.

Open tool

TS1384 and isolatedModules

The `isolatedModules` compiler option is enabled by default in Vite, Next.js, Create React App with Babel, and any project using esbuild or SWC. It requires every file to be independently transformable without cross-file type information, which adds constraints that amplify several TypeScript errors — including TS1384.

What isolatedModules restricts

ConstructWithout isolatedModulesWith isolatedModules
`const enum`✓ Allowed everywhere✗ Only in .d.ts files
`export type`✓ Optional✓ Required for type-only re-exports
`import type`✓ Optional✓ Required for type-only imports
Ambient declarations✓ In any .ts file✓ Better in .d.ts files
Module augmentation✓ In module .ts files✓ Preferred in .d.ts files
Namespace re-exports✓ Allowed✗ Restricted

The isolatedModules-specific fix

When `isolatedModules` is on and TS1384 appears on an augmentation in a regular `.ts` file, the cleanest fix is to move the augmentation into a `.d.ts` file. Declaration files are never transformed by esbuild or Babel — they are read only by the TypeScript compiler. This eliminates the isolatedModules constraint entirely for that augmentation.

src/types/express.d.ts
typescript
// This pattern works correctly with isolatedModules
export {};

declare module 'express' {
  interface Request {
    userId?: string;
    tenantId?: string;
  }
}

Tip

If you are not sure whether `isolatedModules` is enabled in your project, check your tsconfig.json for `"isolatedModules": true`. You can also check your bundler config — Vite's default tsconfig template includes it, and Next.js enables it automatically when using SWC. Use the [Diff Viewer](/tools/data/dev-utilities/diff-viewer) to compare your tsconfig against a known baseline when diagnosing environment-specific TS1384 issues.

TS1384 in .d.ts files

Declaration files add their own nuances to TS1384. The rules for what is valid in a `.d.ts` file differ slightly from regular `.ts` files, and the patterns that produce TS1384 in declaration files are often less intuitive.

The ambient module definition vs augmentation distinction

A `.d.ts` file can contain two fundamentally different things that look similar but behave differently. An ambient module definition (`declare module 'name' ` in a script-context `.d.ts` with no imports or exports) defines all the types for a module from scratch — it is used to type untyped JavaScript libraries. A module augmentation (`declare module 'name' ` in a module-context `.d.ts` with an `export `) extends an existing module's types. The distinction matters because `export` is valid inside an ambient module definition but produces TS1384 inside a module augmentation.

Choosing the right .d.ts pattern

If your `.d.ts` file is defining types for an untyped library (e.g. typing a legacy jQuery plugin), keep it as a script-context file with no `export ` at the top. Use `export` freely inside the `declare module` block. If your `.d.ts` file is augmenting an existing typed library (e.g. adding a property to `Express.Request`), add `export ` at the top and remove any `export` from inside the `declare module` block.

Note

A quick way to determine which pattern applies: if the module you are targeting already has type definitions (via `@types/...` or built-in), you are augmenting. If it has no types at all and you are creating them from scratch, you are writing an ambient module definition.

skipLibCheck as a last resort

When TS1384 fires on a path inside `node_modules` and you have no control over the package, add `"skipLibCheck": true` to your tsconfig.json. This tells TypeScript to skip type checking of all `.d.ts` files — including those in `node_modules`. It is a legitimate, widely-used configuration option, not a hack. The trade-off is that you lose type checking for library declaration files entirely, so genuinely broken types in dependencies will go unreported. Use `skipLibCheck` only when the alternative is blocking your build.

TS1384 in frameworks and bundlers

Different frameworks and build tools configure TypeScript differently, which means TS1384 can surface for slightly different reasons depending on your stack. Here is how the most common environments produce and resolve the error.

Next.js

Next.js enables `isolatedModules` automatically via its default tsconfig and uses SWC for transformation. The standard pattern for type augmentation in Next.js is a dedicated `types/` directory at the project root containing `.d.ts` files with `export ` at the top. Next.js also generates a `next-env.d.ts` file — never edit this file manually, as it is regenerated on each build and any changes will be lost. Add your augmentations to a separate file.

Vite

Vite projects use esbuild for transformation and include `isolatedModules: true` in the default tsconfig. Vite also generates a `vite-env.d.ts` file for its own globals. Add module augmentations in a separate `src/types/` directory. The `export ` pattern resolves TS1384 in all standard Vite setups, and keeping augmentations in `.d.ts` files is the safest approach when esbuild transformation is in the chain.

Plain Node.js / Express APIs

Express projects commonly augment `Express.Request` to add user session or auth context. The canonical pattern is a `src/types/express/index.d.ts` file with `export ` at the top followed by the `declare module 'express-serve-static-core'` augmentation. Without `isolatedModules`, this also works as a regular `.ts` file — but using `.d.ts` is the cleaner convention regardless. Always verify the exact module name by checking the Express type definitions, since the augmentation target is `express-serve-static-core`, not `express` itself.

The file must be a module before it can augment one. One `export ` turns a script into a module — and unlocks the entire augmentation system.

TypeScript module augmentation principle

Avoiding TS1384 long-term

TS1384 is easy to introduce accidentally, especially when new team members add type augmentations or when you migrate a project to a new bundler. These practices prevent it from returning after you fix it.

Establish a types directory convention

Create a `src/types/` (or `types/`) directory and keep all module augmentations there as `.d.ts` files. Each file should contain one augmentation and start with `export `. Document this convention in your project's `CONTRIBUTING.md` so new contributors know where type declarations belong. A consistent location also makes it easy to audit augmentations when upgrading dependencies.

Use tsc --noEmit in CI

Running `tsc --noEmit` as a CI step catches TS1384 (and every other TypeScript error) before code reaches main. Many projects skip type checking in CI because their bundler does not require it — esbuild and SWC strip types without checking them. Add `tsc --noEmit` as a separate job step so type errors, including TS1384, are caught on every pull request.

Use the Diff Viewer to audit tsconfig changes

Changes to tsconfig.json — adding `isolatedModules`, switching `moduleResolution`, or updating `lib` — can introduce TS1384 in files that previously compiled cleanly. When a tsconfig change lands, use the Diff Viewer to compare the old and new config side-by-side. This makes it immediately visible which options changed and helps trace new TS1384 errors to the specific setting that caused them.

Tip

After fixing TS1384, validate your tsconfig.json syntax with the [JSON Formatter and Validator](/tools/data/formatters/json-formatter-viewer) — tsconfig files are JSON, and a trailing comma or missing quote will silently prevent TypeScript from reading the configuration change you just made.

Diff Viewer

Compare two versions of tsconfig.json, package.json, or any text file side-by-side to find exactly what changed — browser-based, no upload required.

Open tool

Key takeaways

  • TS1384 fires when an `export` modifier appears inside a `declare module` or `declare global` augmentation block — the fix is almost always one line.
  • The most common cause: the file has no imports or exports, so TypeScript treats it as a script. Add `export {}` at the top to convert it to a module.
  • With `isolatedModules: true` (Vite, Next.js, esbuild projects), move augmentations to `.d.ts` files — they are excluded from transformation and avoid the constraint entirely.
  • If TS1384 points to a path inside `node_modules`, the fix is `skipLibCheck: true` in tsconfig.json — you cannot edit dependency declaration files.
  • Ambient module definitions (typing untyped libraries) and module augmentations (extending typed libraries) look similar but behave differently — `export` inside the block is only valid in definitions, not augmentations.
  • Add `tsc --noEmit` to your CI pipeline to catch TS1384 on every pull request, even if your bundler (esbuild, SWC) does not perform type checking during the build.
  • Validate tsconfig.json syntax with the JSON Formatter and Validator after changes — a JSON syntax error silently prevents TypeScript from reading your config.

Frequently Asked Questions

TS1384 means TypeScript encountered an `export` modifier in a location where it is not allowed — specifically inside a module augmentation block. The full message is: "'export' modifier cannot be applied to a module augmentation." Module augmentations extend existing types using `declare module '...' {}` or `declare global {}`. They cannot export new symbols — they can only add declarations to an already-existing module. Any `export` inside the augmentation block triggers TS1384.

The most common fix is ensuring the file is a module rather than a script. Add `export {}` at the top if the file has no other imports or exports. This converts it from script context to module context, which TypeScript requires for `declare module` and `declare global` augmentation syntax. If you are trying to add new types rather than augmenting existing ones, move the type declarations outside the `declare module` block.

The `declare global {}` block must be inside a file TypeScript already treats as a module — a file with at least one top-level `import` or `export`. Without one, TypeScript treats the file as a script, and `declare global` in a script file produces TS1384. Add `export {}` at the bottom of the file to force module mode without actually exporting anything. This is the standard pattern for global type augmentation files.

A TypeScript file is a script if it has no top-level `import` or `export` statements — declarations in scripts share a global scope visible to all other script files. A file with at least one `import` or `export` is a module with its own isolated scope. Module augmentation syntax is only allowed in module files. Adding `export {}` — an empty export — converts a script to a module and resolves TS1384 without changing any runtime behaviour.

Yes, in specific scenarios. With `isolatedModules: true` in tsconfig.json, TypeScript requires each file to be independently transformable. Type-only augmentations in regular .ts files can trigger TS1384 when esbuild or Babel tries to process them, because those tools cannot resolve cross-file type information. Moving the augmentation to a .d.ts file resolves it — declaration files are excluded from transformation by all major bundlers.

Yes. If a package ships incorrect type declarations that use `export` inside a module augmentation block, your project emits TS1384 when TypeScript reads those declarations. The pragmatic fix is adding `skipLibCheck: true` to your tsconfig.json, which skips type checking of declaration files in node_modules. This is a workaround — the correct solution is for the package author to fix the declarations. Consider filing an issue on the package repository with the specific TS1384 context.

TS2669 ("Augmentations for the global scope can only be directly nested in external modules or ambient module declarations") is closely related. Both errors fire when the file context is wrong for module augmentation. TS1384 fires when an `export` modifier appears inside the augmentation block itself; TS2669 fires when a `declare global {}` block is in a script file rather than a module. The fix is identical for both: add at least one `import` or `export` statement to the file.

Run `tsc --noEmit` from your project root — TypeScript validates the tsconfig.json and reports configuration errors without generating output files. For JSON syntax errors in tsconfig.json itself (missing commas, trailing commas, wrong property names), paste the file content into the Quasar Tools JSON Formatter and Validator, which highlights syntax problems instantly in your browser without needing the TypeScript compiler installed.

ShareXLinkedIn

Related articles