TypeScript 6.0 Migration Guide: What Web Developers Need to Know

TypeScript 6.0 Migration Guide: Config Tweaks, Deprecations, and Fixes

The team has laid out that the current JavaScript-based compiler (the “Strada” branch) will continue evolving through a 6.x line, with 6.0 introducing some deprecations and breaking changes in preparation for the transition.

Over the last few years, the TypeScript team has made incremental improvements, tightened defaults, and pushed toward a future where the compiler is faster, leaner, and more opinionated. Many changes in TS 5.x were aimed at reducing surprises, improving performance, and aligning with modern JavaScript conventions.

Now, with the upcoming release of TypeScript 6.0, the focus is shifting: 6.0 will serve as a transitional version, preparing for a more radical future — specifically, the “native port” / Go-based compiler (which is expected to debut in TS 7). The changes in 6.0 aim to clean up legacy cruft, enforce more consistent semantics, and simplify internal paths forward.

If you maintain a TypeScript project of any size, migrating to 6.0 will require attention. But the upside is that many breaking changes are relatively mechanical (config tweaks, deprecations) rather than rewriting core logic. Below, I walk you through major config changes, semantic shifts, and concrete migration steps you should consider.

Key changes in TypeScript 6.0 & what they break

Below are the most impactful changes surfaced from GitHub issue discussions (especially the 6.0 Migration Guide #62508) and deprecation proposals. These are the ones that are likely to affect real-world codebases.

baseUrl is no longer required for paths

Historically, if you used paths in your tsconfig.json, you needed to provide a baseUrl so that module resolution knows “where to start.” In TS 6.0, this requirement is relaxed: you can often remove baseUrl entirely (particularly if it was set to "."). If you do still need paths, you may need to prepend the previous baseUrl to each path entry.

There is a helper script, ts-fix-baseurl, which was referenced in the issue to automate rewriting.

Example: Before / After

Before:

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@utils/*": ["src/utils/*"]
    }
  }
}

You may now simplify to:

{
  "compilerOptions": {
    "paths": {
      "@utils/*": ["./src/utils/*"]
    }
  }
}

If your baseUrl was nontrivial (say "src"), you would rewrite each path accordingly:

{
  "compilerOptions": {
    "paths": {
      "@utils/*": ["src/utils/*"]
    }
  }
}

In short: try removing baseUrl, test carefully, and only reintroduce it or adjust paths if resolution breaks.

rootDir default behavior changed

In prior TS versions, if rootDir was left unspecified, the compiler would infer it from the “common root” of all input files. In TS 6.0, the default rootDir is always the directory containing the tsconfig.json file.

This change is made for performance reasons: the compiler no longer needs to analyze the full input graph just to decide the root. That said, this can shift how output paths are organized.

Symptom: after upgrade, your outDir might now include an extra nested folder layer (for example, your emitted files appear under dist/src/... instead of dist/...).

Fix: Explicitly set rootDir in your tsconfig.json.

{
  "compilerOptions": {
    "rootDir": "src",
    "outDir": "dist"
  }
}

Add "include" or "exclude" if needed to cover all source files in the desired directory tree.

Removal of legacy module targets and bundling flags

TS 6.0 proposes removing support for some older/uncommon module options and bundling patterns:

  • module: "amd" and module: "umd" are slated for removal. The team recommends relying on external bundlers (e.g. Rollup, Webpack, esbuild, etc.) for these forms.
  • The --outFile bundling emit is being removed. That is, the built-in bundling ability of TS (combining modules into a single file) is gone. Use a dedicated bundler instead.
  • Other flags to watch: moduleResolution: "classic", esModuleInterop: false, and allowSyntheticDefaultImports: true are being deprecated or disallowed in 6.0.
  • The older module Foo { ... } syntax (instead of namespace Foo { ... }) is being deprecated, because it conflicts with ECMAScript proposals.

If your code or build pipeline depends on any of those, you’ll need to refactor or replace them. And as Ryan Cavanaugh noted in the linked GitHub issue above:

We’re planning the following set of deprecations for TypeScript 6.0. While TypeScript 6.0 will follow the same “soft deprecation” strategy as TypeScript 5.0, these options will be removed entirely in TypeScript 7 (the native TypeScript port).

New default for types

A big change: currently, TypeScript automatically includes all .d.ts files under node_modules/@types (unless excluded). In TS 6.0, the default will be types: [] — i.e. no automatic ambient types.

What this means:

  • Modules imported by name (e.g. import fs from "fs") will still resolve their types if they ship their own types or have corresponding @types/* packages installed.
  • But ambient-global types (e.g. @types/node, @types/jest, or legacy global types) will no longer be auto-included.

So in most projects you must explicitly specify:

{
  "compilerOptions": {
    "types": ["node", "jest"]
  }
}

Failing to do this often leads to “cannot find name ‘process’” or “fs module not found” errors.

Migration strategy: step by step

Below is a realistic approach to migrating your codebase to TS 6.0 with minimal disruption.

1. Run on 5.x with strict flags / warnings

Before jumping to 6.0, start by enabling stricter settings in TS 5.x (e.g. --strict, no legacy module flags) so you catch edge cases early. Also, track deprecation warnings in TypeScript releases leading up to 6.0 (especially via the “6.0 Deprecation Candidates” issue).

2. Upgrade locally / in a branch

Install TS 6.0 in a side branch or local environment. Do not commit upstream until things pass. Try an incremental approach.

3. Adjust tsconfig.json

  • Set rootDir explicitly where needed to control your output structure.
  • Add types entries explicitly for ambient types currently used.
  • Remove or adjust baseUrl / paths usage: test resolution, and use helper scripts to rewrite paths if needed.
  • Drop unsupported module/emit flags, e.g. remove outFile, avoid amd or umd.
  • Audit legacy module {} syntax and convert to namespace if used.

4. Fix resolution / import errors

With types: [], ensure all externals or globals have their declarations configured. Fix import paths broken by baseUrl changes. Watch for name resolution changes (e.g. the cross-namespace qualification change noted in deprecations discussions).

5. Test builds, emits, and runtimes

Run your full build, run tests, and verify output structure. Pay attention to any missing type or module resolution errors. If your bundler integration breaks (esp. for AMD/UMD), migrate those parts to a bundler plugin or newer tool.

6. Incrementally adopt the native compiler (future)

Because 6.0 is essentially a bridge to the native Go-based compiler, maintain compatibility in your code so that you can later switch to the native build when it’s stable. Avoid relying on internal TS behaviors that might not be preserved.

What to watch out for (gotchas & edge cases)

  • If your project uses ambient global types (e.g. @types/jquery that globally expose $), you must explicitly include them via the new types setting, or they’ll vanish.
  • If your tsconfig.json sat in a non-root folder (monorepo or nested), the new rootDir default may bite you unexpectedly — explicit rootDir is safer.
  • Some legacy bundling code (that relied on TS doing concatenation or legacy module systems) may fail. You’ll need to offload that to modern build tools.
  • The semantic change about cross-namespace lookup (one of the deprecation candidates) may cause previously ambiguous references to resolve differently.

Conclusion

TypeScript 6.0 is a meaningful evolution rather than a radical rewrite. Its goal is to clean up legacy behavior, tighten defaults, and pave the way for a faster native compiler in TS 7. The biggest migration burden lies in config changes (especially types, rootDir, baseUrl/paths) and removing older module & bundling patterns.

If you approach 6.0 migration through careful steps—upgrade locally, adjust config first, then fix import/type resolution—you can make the transition relatively smooth. And once your project is “6.0 ready,” you’ll be better positioned to later adopt the native compiler with fewer surprises.

Was this helpful?

Thanks for your feedback!

Leave a comment

Your email address will not be published. Required fields are marked *