TypeScript 6.0: 3 Breaking Changes That Hit My NestJS Project

Published: 2026-06-27

Dependabot opened a dev-tooling upgrade PR: TypeScript 5.9.3 β†’ 6.0.3, ESLint 9 β†’ 10. I merged it. The ESLint changes were minor. Then I ran pnpm build.

This post covers three compiler errors from that upgrade β€” the ones that came from how the project was configured and how NestJS initializes class properties outside the constructor. In the order I hit them.


TS5011 β€” rootDir Is No Longer Inferred

In TypeScript 5, rootDir was inferred automatically from the common source directory of all input files. TypeScript 6 changed the default to . β€” the directory containing tsconfig.json β€” and now requires it to be set explicitly.1

The NestJS scaffold’s tsconfig.json has no explicit rootDir β€” though outDir is set, which is why the missing rootDir surfaces on upgrade:

{
  "compilerOptions": {
    "outDir": "./dist"
  }
}

The obvious fix is to add "rootDir": "./src" to tsconfig.json. Don’t.

If you add it there, the compiler immediately throws a second error:

error TS6059: File 'test/app.e2e-spec.ts' is not under 'rootDir' './src'.
  'rootDir' is expected to contain all source files.

NestJS’s default tsconfig.json has no include or exclude β€” it picks up everything in the project, including test/. Setting rootDir: "./src" while test/ is still in scope is a contradiction.

The correct fix is to add rootDir only to tsconfig.build.json, which already excludes test/:

// tsconfig.build.json β€” before
{
  "extends": "./tsconfig.json",
  "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
}
// tsconfig.build.json β€” after
{
  "extends": "./tsconfig.json",
  "exclude": ["node_modules", "test", "dist", "**/*spec.ts"],
  "compilerOptions": {
    "rootDir": "./src"
  }
}

tsconfig.build.json is what nest build uses. Since test/ is already excluded there, rootDir: "./src" is valid. The base tsconfig.json β€” used by your IDE and ts-jest β€” stays unchanged.


TS5101 β€” baseUrl Promoted to Error

baseUrl was fully supported in TypeScript 5 with no warnings. TypeScript 6.0 deprecated it and enforces the deprecation immediately as a compile error.2

error TS5101: Option 'baseUrl' is deprecated and will stop functioning in TypeScript 7.0.
  Specify compilerOption '"ignoreDeprecations": "6.0"' to silence this error.

The NestJS scaffold includes baseUrl in tsconfig.json β€” a common path-resolution setting that was previously harmless:

{
  "compilerOptions": {
    "baseUrl": "./"
  }
}

The right long-term fix is to migrate to path aliases using only paths β€” baseUrl is being removed as a module lookup root, and paths entries work without it. But that’s a larger refactor.

The practical short-term fix, and the one the error message recommends:

{
  "compilerOptions": {
    "baseUrl": "./",
    "ignoreDeprecations": "6.0"
  }
}

This silences the error and buys time until TypeScript 7. Add it to tsconfig.json β€” it applies to all extends, including tsconfig.build.json.


TS2564 β€” strictPropertyInitialization Now On by Default

strictPropertyInitialization is part of strict mode and was off by default in TypeScript 5 unless strict: true was set. TypeScript 6 made strict: true the default, which activates it β€” along with every other strict flag β€” for projects that hadn’t opted in before.3

error TS2564: Property 'ws' has no initializer and is not definitely assigned in the constructor.
error TS2564: Property 'server' has no initializer and is not definitely assigned in the constructor.
error TS2564: Property 'workerUtils' has no initializer and is not definitely assigned in the constructor.

All three of these properties follow the same NestJS pattern: they are declared on the class but initialized outside the constructor β€” either in a lifecycle hook or via a decorator.

// FinnhubService β€” initialized in onModuleInit()
@Injectable()
export class FinnhubService implements OnModuleInit {
  private ws: WebSocket; // TS2564

  onModuleInit() {
    this.ws = new WebSocket('wss://ws.finnhub.io?token=...');
  }
}
// PricesGateway β€” injected by the @WebSocketServer() decorator
@WebSocketGateway()
export class PricesGateway {
  @WebSocketServer()
  server: Server; // TS2564
}
// QueueService β€” initialized asynchronously in onModuleInit()
@Injectable()
export class QueueService implements OnModuleInit {
  private workerUtils: WorkerUtils; // TS2564

  async onModuleInit() {
    this.workerUtils = await makeWorkerUtils({ connectionString: process.env.DATABASE_URL });
  }
}

TypeScript can’t verify that these properties are set before use β€” the initialization happens in framework-controlled lifecycle methods, not the constructor. The fix is the definite assignment assertion !, which tells the compiler you are taking responsibility:

private ws!: WebSocket;
server!: Server;
private workerUtils!: WorkerUtils;

Before adding ! to every flagged property, verify the property actually is initialized before first use. The NestJS lifecycle guarantees onModuleInit() runs before the module handles any requests, and @WebSocketServer() is populated before the gateway handles events. These three are safe.

A genuinely uninitialized property would be a real bug β€” the ! would just hide it.


Upgrade Order

If you hit all three errors at once, apply them in this order:

  1. tsconfig.build.json β€” add rootDir. Eliminates TS5011.
  2. tsconfig.json β€” add ignoreDeprecations. Eliminates TS5101.
  3. Class properties β€” add ! case by case. Eliminates TS2564.

Confirm the build passes after steps 1 and 2 before touching class properties. If more errors surface after adding rootDir, they were hidden by the missing rootDir and are genuine issues worth addressing separately.


Summary

ErrorTypeScript 5TypeScript 6Fix
TS5011rootDir inferred automaticallyrootDir must be explicitAdd to tsconfig.build.json only
TS5101baseUrl: fully supportedbaseUrl: compile error"ignoreDeprecations": "6.0"
TS2564strictPropertyInitialization offon by default! assertion on lifecycle-owned properties

Further Reading

Footnotes

  1. TypeScript 6.0 release notes β€” rootDir now defaults to the tsconfig directory. Previously inferred from the common source directory; now always defaults to the tsconfig.json directory. ↩

  2. TypeScript 6.0 release notes β€” Deprecated: β€”baseUrl. baseUrl is deprecated in TS6 and immediately enforces as a compile error; ignoreDeprecations: "6.0" silences it. ↩

  3. TypeScript 6.0 release notes β€” Simple Default Changes. strict now defaults to true, which activates strictPropertyInitialization and all other strict-mode flags. ↩