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:
tsconfig.build.jsonβ addrootDir. Eliminates TS5011.tsconfig.jsonβ addignoreDeprecations. Eliminates TS5101.- 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
| Error | TypeScript 5 | TypeScript 6 | Fix |
|---|---|---|---|
| TS5011 | rootDir inferred automatically | rootDir must be explicit | Add to tsconfig.build.json only |
| TS5101 | baseUrl: fully supported | baseUrl: compile error | "ignoreDeprecations": "6.0" |
| TS2564 | strictPropertyInitialization off | on by default | ! assertion on lifecycle-owned properties |
Further Reading
- TypeScript 6.0 release notes β covers rootDir enforcement, default changes, and the deprecation promotion policy.
- TypeScript 6.0 β ignoreDeprecations β versioned opt-in for suppressing deprecated-option errors; note the release notes explicitly say this is a temporary bridge, not a long-term feature.
- TypeScript 6.0 + Zod v4: ReturnType collapses to unknown β a fourth error from the same upgrade batch, triggered by the interaction between TypeScript 6βs stricter inference and Zod v4βs new
parse()return type.
Footnotes
-
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. β©
-
TypeScript 6.0 release notes β Deprecated: βbaseUrl.
baseUrlis deprecated in TS6 and immediately enforces as a compile error;ignoreDeprecations: "6.0"silences it. β© -
TypeScript 6.0 release notes β Simple Default Changes.
strictnow defaults totrue, which activatesstrictPropertyInitializationand all other strict-mode flags. β©