How to fix Decorators are not valid on parameters unless 'emitDecoratorMetadata' is enabled in TypeScript

TypeScriptINTERMEDIATEMEDIUMUpdated Dec 8, 2025· 201 views

This TypeScript error occurs when you use parameter decorators without enabling the emitDecoratorMetadata compiler option. Parameter decorators rely on metadata reflection to function properly, which requires both experimentalDecorators and emitDecoratorMetadata to be enabled in tsconfig.json.

Quick fix

Fixes Decorators are not valid on parameters unless 'emitDecoratorMetadata' is enabled

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "target": "ES2020",
    "module": "commonjs"
  }
}
  1. Enable emitDecoratorMetadata in tsconfig.json
  2. Install and import reflect-metadata
  3. Verify tsconfig.json is being used
  4. Check for TypeScript 5.0+ standard decorator conflicts
typescript — error
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"target": "ES2020",
"module": "commonjs"
}
}
Decorators are not valid on parameters unless 'emitDecoratorMetadata' is enabled

What this error means

Parameter decorators are a TypeScript feature that allows you to attach metadata to function or method parameters. They are commonly used in dependency injection frameworks like NestJS, Angular, and InversifyJS to automatically resolve dependencies at runtime. When TypeScript compiles code with parameter decorators, it needs to emit type metadata that describes the parameter types. This metadata is stored using the reflect-metadata library and accessed at runtime. Without the emitDecoratorMetadata option enabled, TypeScript cannot emit this critical type information, causing the compiler to reject parameter decorators entirely. This error is distinct from general decorator errors because parameter decorators specifically require metadata reflection. While class, method, and property decorators can work without emitDecoratorMetadata, parameter decorators cannot function without knowing the runtime types of parameters—information only available through metadata emission. The error commonly appears in dependency injection scenarios where frameworks need to know what types to inject into constructor or method parameters.

Typical symptoms

  • TypeScript compiler error when using @Inject(), @Param(), or custom parameter decorators
  • Error specifically mentions parameter decorators and emitDecoratorMetadata
  • Code works in JavaScript but fails TypeScript compilation
  • Dependency injection frameworks like NestJS fail to compile
  • Parameter decorators on constructor parameters trigger compilation errors
  • IDE (VS Code, WebStorm) shows red underlines on parameter decorators

Common causes

  1. emitDecoratorMetadata is not set to true in tsconfig.json
  2. experimentalDecorators is disabled (both flags required for parameter decorators)
  3. Using TypeScript 5.0+ standard decorators which don't support parameter decorators
  4. tsconfig.json is not being read correctly (wrong directory or extends chain broken)
  5. reflect-metadata package not installed or imported in entry file
  6. Multiple tsconfig files with conflicting settings in a monorepo
  7. Attempting to use parameter decorators with isolatedModules: true (limited support)

How to fix "Decorators are not valid on parameters unless 'emitDecoratorMetadata' is enabled"

1Enable emitDecoratorMetadata in tsconfig.json

Open your tsconfig.json file and ensure both experimentalDecorators and emitDecoratorMetadata are enabled:

json
{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "target": "ES2020",
    "module": "commonjs"
  }
}

Both flags are required:
- experimentalDecorators: Enables decorator syntax
- emitDecoratorMetadata: Emits type metadata for parameters

Save the file and restart your TypeScript server in your IDE (VS Code: Cmd+Shift+P → "TypeScript: Restart TS Server").

2Install and import reflect-metadata

Parameter decorators require the reflect-metadata polyfill to store and retrieve type information at runtime.

Install it as a dependency (not devDependency):

bash
npm install reflect-metadata
# or
yarn add reflect-metadata
# or
pnpm add reflect-metadata

Then import it at the very top of your application entry file (usually main.ts, index.ts, or app.ts):

typescript
// main.ts - FIRST import, before anything else
import "reflect-metadata";

import { NestFactory } from "@nestjs/core";
import { AppModule } from "./app.module";

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);
}
bootstrap();

This polyfill must be loaded before any decorators are evaluated.

3Verify tsconfig.json is being used

Ensure TypeScript is actually reading your tsconfig.json file:

bash
# Check which config file TypeScript is using
npx tsc --showConfig

Common issues:

Wrong directory: Make sure you're running tsc from the directory containing tsconfig.json

Extends chain broken: If you use extends, verify the base config exists:

json
{
  "extends": "./tsconfig.base.json",  // Must exist
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

Multiple configs in monorepo: Ensure the correct tsconfig is being used for your package:

bash
# Compile with specific config
npx tsc -p packages/api/tsconfig.json
4Check for TypeScript 5.0+ standard decorator conflicts

TypeScript 5.0 introduced standard ECMAScript decorators, which are NOT compatible with parameter decorators or emitDecoratorMetadata.

If you're using TypeScript 5.0+, you MUST use legacy decorators (experimentalDecorators) for parameter decorators to work:

json
{
  "compilerOptions": {
    "experimentalDecorators": true,  // REQUIRED for parameter decorators
    "emitDecoratorMetadata": true,
    "target": "ES2022"
  }
}

Important: Standard decorators (without experimentalDecorators) do NOT support:
- Parameter decorators at all
- emitDecoratorMetadata
- Design-time type reflection

If you need parameter decorators (for dependency injection), you must use legacy decorators.

5Update build tools and frameworks

Ensure your build tools respect tsconfig.json decorator settings:

For ts-node:

json
// tsconfig.json
{
  "ts-node": {
    "compilerOptions": {
      "experimentalDecorators": true,
      "emitDecoratorMetadata": true
    }
  }
}

Or use command line flags:

bash
ts-node --experimental-decorators --emit-decorator-metadata src/main.ts

For webpack with ts-loader:

javascript
// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        loader: "ts-loader",
        options: {
          compilerOptions: {
            experimentalDecorators: true,
            emitDecoratorMetadata: true,
          },
        },
      },
    ],
  },
};

For NestJS: The default NestJS tsconfig already includes these settings. If you customized it, restore them.

6Fix isolatedModules conflicts if present

If you're using isolatedModules: true (common with Babel, esbuild, or SWC), you may encounter limitations with decorators.

Check your configuration:

json
{
  "compilerOptions": {
    "isolatedModules": true,  // Can cause issues
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

Workaround options:

1. Use tsc for type checking, fast bundler for builds:

json
// tsconfig.build.json (for esbuild/swc)
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "isolatedModules": false  // Only for type checking
  }
}

2. Use SWC with decorator support:

javascript
// .swcrc
{
  "jsc": {
    "parser": {
      "syntax": "typescript",
      "decorators": true
    },
    "transform": {
      "legacyDecorator": true,
      "decoratorMetadata": true
    }
  }
}

Run type checking separately: npx tsc --noEmit

Advanced notes

### How emitDecoratorMetadata Works

When enabled, TypeScript emits three types of metadata for decorated elements:

typescript
class UserService {
  constructor(@Inject() private db: DatabaseService) {}
}

// TypeScript emits (conceptually):
// design:type - the type of the decorated element
// design:paramtypes - parameter types (for constructors/methods)
// design:returntype - return type (for methods)

For the constructor above, TypeScript emits:

javascript
__metadata("design:paramtypes", [DatabaseService])

The dependency injection framework reads this at runtime to know to inject a DatabaseService instance.

### NestJS and Dependency Injection

NestJS heavily relies on parameter decorators for dependency injection:

typescript
import "reflect-metadata";
import { Injectable, Controller, Get, Param } from "@nestjs/common";

@Injectable()
export class UsersService {
  findOne(id: string) {
    return { id, name: "John" };
  }
}

@Controller("users")
export class UsersController {
  // Parameter decorator @Param requires emitDecoratorMetadata
  constructor(private usersService: UsersService) {}

  @Get(":id")
  findOne(@Param("id") id: string) {
    return this.usersService.findOne(id);
  }
}

Without emitDecoratorMetadata, NestJS cannot determine that UsersService should be injected into the constructor.

### Standard Decorators vs Legacy Decorators

TypeScript 5.0 introduced standard ECMAScript decorators, but they have critical limitations:

| Feature | Legacy (experimentalDecorators) | Standard (TS 5.0+) |
|---------|--------------------------------|---------------------|
| Parameter decorators | ✅ Supported | ❌ Not supported |
| emitDecoratorMetadata | ✅ Supported | ❌ Not supported |
| Type reflection | ✅ Available | ❌ Not available |
| Future standard | ⚠️ May change | ✅ ES standard |

For dependency injection frameworks, you MUST use legacy decorators.

### Monorepo Considerations

In monorepos with multiple packages, ensure each package that uses parameter decorators has the correct tsconfig:

bash
monorepo/
├── packages/
│   ├── api/
│   │   └── tsconfig.json  ← Must have flags
│   ├── shared/
│   │   └── tsconfig.json  ← Must have flags
│   └── web/
│       └── tsconfig.json  ← May not need them
└── tsconfig.base.json     ← Can set here too

Base config approach:

json
// tsconfig.base.json
{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

// packages/api/tsconfig.json
{
  "extends": "../../tsconfig.base.json"
}

### Performance Implications

emitDecoratorMetadata adds metadata to your compiled JavaScript, slightly increasing bundle size. For most applications this is negligible, but if bundle size is critical:

1. Use tree-shaking to remove unused metadata
2. Only enable in packages that need it
3. Consider alternative DI patterns that don't require decorators

### Debugging Metadata

To verify metadata is being emitted, inspect compiled JavaScript:

bash
npx tsc --outFile output.js src/main.ts
cat output.js | grep "design:paramtypes"

You should see lines like:

javascript
__metadata("design:paramtypes", [DatabaseService, LoggerService])

If these are missing, metadata emission failed.

Frequently asked questions

What does "Decorators are not valid on parameters unless 'emitDecoratorMetadata'" mean?
Parameter decorators are a TypeScript feature that allows you to attach metadata to function or method parameters. They are commonly used in dependency injection frameworks like NestJS, Angular, and InversifyJS to automatically resolve dependencies at runtime. When TypeScript compiles code with parameter decorators, it needs to emit type metadata that describes the parameter types.
How do I fix "Decorators are not valid on parameters unless 'emitDecoratorMetadata'"?
This TypeScript error occurs when you use parameter decorators without enabling the emitDecoratorMetadata compiler option. Parameter decorators rely on metadata reflection to function properly, which requires both experimentalDecorators and emitDecoratorMetadata to be enabled in tsconfig.json.
What causes "Decorators are not valid on parameters unless 'emitDecoratorMetadata'"?
emitDecoratorMetadata is not set to true in tsconfig.json experimentalDecorators is disabled (both flags required for parameter decorators) Using TypeScript 5.0+ standard decorators which don't support parameter decorators
Is the "Decorators are not valid on parameters unless 'emitDecoratorMetadata'" error serious?
It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.

Official resources & further reading