DevBolt
By The DevBolt Team··11 min read

TypeScript 6.0 vs 5.x: Complete Migration Guide

TypeScriptMigrationtsconfigGuide

TypeScript 6.0 went GA on March 17, 2026, and it is the most opinionated major release since TypeScript adopted strict mode. Default compiler settings have changed, legacy targets have been removed, and several deprecated options are now errors. This guide walks through every breaking change, what they mean for your codebase, and how to migrate with confidence.

Want to check your tsconfig.json automatically? Use DevBolt's TypeScript 6.0 Migration Checker to analyze your config and get a readiness grade with fix instructions.

What Changed in TypeScript 6.0

TypeScript 6.0 makes three categories of changes: removed options that are now compile errors, new defaults that change behavior even with no config changes, and deprecated options that still work but emit warnings. Here is the full breakdown.

Removed Options (Breaking)

These options existed in TypeScript 5.x but are now compile errors in 6.0. If your tsconfig.json uses any of them, the compiler will refuse to run.

ES3 and ES5 Targets Removed

Setting "target": "es3" or "target": "es5" is now an error. TypeScript 6.0 requires at least ES2015 (ES6) as the compilation target. The rationale is straightforward: no maintained browser or runtime requires ES5 output in 2026. IE11 was discontinued in June 2022, and even legacy enterprise environments have moved on.

How to fix: Change your target to "es2020" or later. If you were targeting ES5 for broad compatibility, "es2020" covers 97%+ of browsers. For Node.js projects, match your Node version: "es2022" for Node 18, "es2023" for Node 20.

tsconfig.json — before
{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "es5"]
  }
}
tsconfig.json — after
{
  "compilerOptions": {
    "target": "es2020",
    "lib": ["dom", "es2020"]
  }
}

outFile Removed

The outFile option (which concatenated all output into a single file) has been removed. This feature only worked with AMD and SystemJS modules, both of which are also removed. Modern bundlers like Vite, esbuild, and webpack handle bundling far more effectively.

How to fix: Remove outFile from your config. Use a dedicated bundler for single-file output. If you are building a library, use outDir instead and let your bundler handle the final output.

AMD, UMD, and System Module Formats Removed

Setting "module": "amd", "module": "umd", or "module": "system" is now an error. These module formats were designed for a pre-ESM world. ESM (ES Modules) and CommonJS are the only module formats that matter in 2026.

How to fix: Switch to "module": "esnext" for ESM projects (recommended) or "module": "commonjs" for legacy Node.js CJS projects. If you were using UMD for browser globals, use a bundler with UMD output format instead.

moduleResolution "classic" and "node" Removed

The original "moduleResolution": "classic" (TypeScript's legacy resolver) and the confusingly named "moduleResolution": "node" (which was Node 10-era resolution, now called node10) are both removed.

How to fix: Use "moduleResolution": "bundler" for apps built with Vite, Next.js, or webpack. Use "moduleResolution": "node16" or "moduleResolution": "nodenext" for pure Node.js packages that need strict ESM/CJS resolution.

Changed Defaults

These are the most subtle breaking changes. Even if you do not modify your tsconfig.json, TypeScript 6.0 will behave differently because the implicit defaults have changed.

OptionTS 5.x DefaultTS 6.0 Default
strictfalsetrue
targetes3es2025
modulecommonjsesnext
moduleResolutionnode10bundler
rootDirInferred from files.
typesAll @types/*[] (empty)
noUncheckedSideEffectImportsfalsetrue
esModuleInteropfalsetrue (locked)
allowSyntheticDefaultImportsfalsetrue (locked)

strict: true by Default

This is the biggest behavioral change. In TypeScript 5.x, strict mode was opt-in. In 6.0, it is on by default. This means strictNullChecks, strictFunctionTypes, strictBindCallApply, strictPropertyInitialization, noImplicitAny, noImplicitThis, alwaysStrict, and useUnknownInCatchVariables are all enabled unless you explicitly set "strict": false.

Impact: If your project did not have "strict": true in tsconfig, you will see new type errors — potentially hundreds in a large codebase. The most common are null checks (Object is possibly null) and implicit any parameters.

How to fix: If your codebase is not ready for strict mode, explicitly add "strict": false to your config. For a gradual migration, keep "strict": false and enable individual flags one at a time: strictNullChecks first, then noImplicitAny, and so on.

types: [] by Default

In TypeScript 5.x, omitting the types field meant "include all @types/* packages in node_modules." In 6.0, the default is an empty array — no type packages are included automatically. This means @types/node, @types/react, and similar packages must be explicitly listed.

tsconfig.json — explicit types
{
  "compilerOptions": {
    "types": ["node", "react", "jest"]
  }
}

noUncheckedSideEffectImports: true

Side-effect imports like import "./styles.css" or import "reflect-metadata" are now checked by default. If the imported module does not exist or has no type definition, TypeScript will report an error. This catches typos in side-effect imports that previously failed silently at runtime.

How to fix: For CSS/SCSS imports in bundler-based projects, ensure you have a declaration file (or use "moduleResolution": "bundler" which is now the default). For custom side-effect modules, add a .d.ts declaration file.

Deprecated Options (Warnings)

These options still work in TypeScript 6.0 but emit deprecation warnings. They will likely be removed in TypeScript 7.0. Fix them now to avoid a harder migration later.

  • baseUrl without path aliases — if you are only using baseUrl for non-relative imports (like import "src/utils"), use paths instead. baseUrl is still valid when used alongside paths.
  • downlevelIteration — no longer needed when targeting ES2015+ (which is now required). Remove it.
  • "alwaysStrict": false — contradicts the new strict-by-default behavior. Either enable strict mode or use "strict": false to opt out entirely.
  • "esModuleInterop": false — this is now locked to true. Setting it to false emits a warning and is ignored.

Step-by-Step Migration Checklist

Follow these steps to migrate a TypeScript 5.x project to 6.0:

  1. 1Run the Migration Checker. Paste your tsconfig.json into DevBolt's TypeScript 6.0 Migration Checker to get a readiness grade and prioritized list of issues.
  2. 2Update your target. Replace "target": "es5" with "target": "es2020" or later. Update lib to match.
  3. 3Switch module and moduleResolution. Use "module": "esnext" and "moduleResolution": "bundler" for apps. Use "module": "node16" and "moduleResolution": "node16" for Node.js libraries.
  4. 4Remove outFile. Delete it and use your bundler for single-file output.
  5. 5Handle strict mode. If your project already had "strict": true, no change needed. If not, either add "strict": false to preserve current behavior, or start fixing type errors (recommended).
  6. 6Add explicit types. List all @types/* packages in the types array: "types": ["node", "react", "jest"].
  7. 7Remove deprecated options. Delete downlevelIteration, standalone baseUrl, and "esModuleInterop": false.
  8. 8Run tsc --noEmit. Fix any remaining errors. Most will be strict-mode type issues.
  9. 9Update CI. Pin typescript@6 in your lockfile and CI config. Run your full test suite.

Example: Migrating a Next.js Project

Here is a real-world before/after for a typical Next.js App Router project:

tsconfig.json — TypeScript 5.x
{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules"]
}
tsconfig.json — TypeScript 6.0
{
  "compilerOptions": {
    "target": "es2022",
    "lib": ["dom", "dom.iterable", "es2022"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "types": ["node", "react", "react-dom"]
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules"]
}

Key changes: target moved from es5 to es2022, moduleResolution changed from node to bundler, esModuleInterop and allowSyntheticDefaultImports removed (now default), and types explicitly listed.

The Escape Hatch: ignoreDeprecations

TypeScript 6.0 provides an escape hatch for deprecated (not removed) options:

Suppress deprecation warnings
{
  "compilerOptions": {
    "ignoreDeprecations": "6.0"
  }
}

This silences deprecation warnings but does not restore removed options. Use it as a temporary measure during migration, not as a permanent solution. These options will be fully removed in a future version.

Looking Ahead: TypeScript 7.0

TypeScript 7.0 is expected to be the most significant TypeScript release ever — a complete rewrite of the compiler in Go, promising 7-10x compilation speed improvements. The 6.0 cleanup of legacy options is preparation for this rewrite. Migrating to 6.0 now ensures your codebase is ready for the Go-based compiler when it ships.

Start your migration today. Use the TypeScript 6.0 Migration Checker to analyze your config, and the tsconfig.json Visual Builder to generate a clean config from scratch.