August 14, 2026

TypeScript 7: What Actually Breaks When You Upgrade (and Why Your Build May Still Be on 6)

Photo of Marco Orta Marco Orta | 12 mins read
Compartir
A blue TypeScript gear cracking apart while a compiler written in Go races ahead
Table of Contents

    TypeScript 7 went stable on July 8, 2026, and today npm install typescript gives you 7. This is not a beta you have to opt into: it is what sits behind the latest tag.

    Which means you can end up on TypeScript 7 without deciding to — an npm install in a project with no lockfile, a Dependabot bump, a teammate cloning the repo. And unlike almost every previous TypeScript major, this one removes configuration options instead of merely warning that it will.

    The headline is real: the compiler has been rewritten in Go and is roughly ten times faster. I measured it on this very site and got 11.1×, using half the memory. But the headline hides the part that matters, which is what stops working the day you bump the version.

    This article is that list, with the error messages exactly as the compiler prints them. If what you want is what TypeScript is and why to use it, that lives in the introduction to TypeScript and static typing; here we go straight to what breaks.

    First: does this affect you yet?

    Check what you are actually running:

    npx tsc --version
    npm view typescript dist-tags
    

    As of today, latest is 7.0.2. If your package.json says "typescript": "^6.0.0" you are safe: ^ never crosses a major. If it says "typescript": "*", ">=6", or pins nothing at all, your next clean install moves you up.

    The distinction that matters: TypeScript 7 is not a new compiler sitting next to the old one. During the preview they coexisted, and the Go compiler shipped separately as @typescript/native-preview with a tsgo binary. From the RC onward that folded back in: the same typescript package and the same tsc command are the Go compiler now. You do not change commands. You change configuration.

    What you gain: measured, not copied from the announcement

    The official numbers come from huge repositories — vscode drops from 125.7 s to 10.6 s (11.9×), sentry from 139.8 s to 15.7 s (8.9×), bluesky from 24.3 s to 2.8 s (8.7×). Impressive, but it leaves the obvious question: what about a normal project that does not have 1.5 million lines?

    I measured it on this site’s own code: 162 .ts/.tsx files, 32,791 lines, Node 24.16.0 on WSL2, same tsconfig, same hardware, three runs after a warm-up, best time kept.

    TypeScript 6.0.3TypeScript 7.0.2Difference
    tsc --noEmit2,281 ms206 ms11.1× faster
    Peak memory (RSS)430,716 kB195,540 kB−55%

    Two things worth stating honestly. First: the gain does not require a giant monorepo. A 33,000-line project gets the same multiplier as vscode.

    Second, the check that makes the number mean anything: both compilers reported 305 errors, the exact same error codes, spread across the same 76 files. If TypeScript 7 had been fast because it gave up earlier, it would show here. It does not give up earlier — it does identical work in a eleventh of the time.

    On memory my drop (−55%) is considerably larger than the official vscode figure (−18%). I have no solid explanation for that gap and I am not going to invent one; treat it as one project’s measurement, not a promise.

    What disappears from tsconfig.json

    This is the bulk of the migration. These options are not deprecated: they are removed, and the compiler refuses to start.

    1. baseUrl — the one that will hit you

    By far the most widespread. Any project with @/components/... style imports has it.

    { "compilerOptions": { "baseUrl": "./src", "paths": { "@/*": ["*"] } } }
    
    error TS5102: Option 'baseUrl' has been removed. Please remove it from your configuration.
      Use '"paths": {"*": ["./src/*"]}' instead.
    error TS5090: Non-relative paths are not allowed. Did you forget a leading './'?
    

    The fix is to rewrite paths relative to the project root, with a leading ./, and delete baseUrl:

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

    Watch that second error, TS5090: removing baseUrl is not enough. If you leave the paths as ["*"] without the ./, it still fails. That is two changes, not one.

    2. target: "es5"

    error TS5108: Option 'target=ES5' has been removed. Please remove it from your configuration.
    

    There is no replacement: if you genuinely need ES5 output, that job moves to your bundler or to Babel. The compiler floor is now ES2015.

    3. downlevelIteration

    error TS5102: Option 'downlevelIteration' has been removed. Please remove it from your configuration.
    

    A natural consequence of the previous one: it only ever made sense for downleveling iterators to ES5.

    4. moduleResolution: "node" and "classic"

    error TS5108: Option 'moduleResolution=node10' has been removed. Please remove it from your configuration.
    

    Note the detail: you write "node" and the error talks about node10. Same value, modern name — so do not go hunting for where you wrote node10. The recommended replacements are nodenext (if you resolve like Node) or bundler (if you bundle with Vite, esbuild or similar).

    5. module: "amd", "umd", "systemjs" and "none"

    This one deserves its own warning because the message misleads:

    error TS5095: Option 'bundler' can only be used when 'module' is set to 'preserve', 'commonjs', or 'es2015' or later.
    error TS5108: Option 'module=AMD' has been removed. Please remove it from your configuration.
    

    The first error mentions bundler, an option you never wrote. It shows up because bundler is now the default resolution and it clashes with your inherited module. The real error is the second one. Switch module to esnext or preserve and both vanish together.

    6. The ones that can no longer be false

    esModuleInterop, allowSyntheticDefaultImports and alwaysStrict still exist, but only as true. Setting them to false is an error:

    error TS5108: Option 'esModuleInterop=false' has been removed. Please remove it from your configuration.
    error TS5108: Option 'alwaysStrict=false' has been removed. Please remove it from your configuration.
    

    In practice this only bites older projects that carried esModuleInterop: false to avoid touching CommonJS imports. If that is you, the real work is not the tsconfig: it is turning import * as x from 'y' into import x from 'y'.

    What breaks outside tsconfig: the API that does not exist

    This is the part that sinks more migrations than every option above combined, and it never appears in a compiler error message.

    TypeScript 7.0 ships no programmatic API. The announcement says it plainly — “TypeScript 7.0 does not ship with an API” — and places the new one, different from today’s, in 7.1.

    Any tool that does not merely run tsc but imports TypeScript to walk the AST or ask it for types is locked out. And it does not fail gracefully: the whole npm install aborts.

    npm error code ERESOLVE
    npm error Found: [email protected]
    npm error Could not resolve dependency:
    npm error peer typescript@">=4.8.4 <6.1.0" from [email protected]
    

    That >=4.8.4 <6.1.0 range is what typescript-eslint publishes today: it excludes 7 by design. And because npm fails the whole resolution, nothing installs — not even TypeScript. It is not that your linter ends up half-broken: the project does not install.

    Everyone affected for the same reason:

    • typescript-eslint — the case above.
    • ts-jest — worse here, because it fails at run time rather than install time, with stack traces about compiler internals that no longer exist.
    • ts-morph and any code generator or codemod that manipulates the AST.
    • Vue, Svelte, MDX and Astro — their template type-checkers use the API. The announcement itself warns that “workflows that use Vue, MDX, Astro, Svelte, and others will likely not yet be able to leverage TypeScript 7”.

    That last point is not theoretical for me: this site runs Astro 7 and is still on TypeScript 6.0.3 precisely because of it. @astrojs/check depends on the API. I can use the Go compiler to benchmark, but I cannot put 7 in package.json without losing type checking inside .astro files. If you arrived from the guide to upgrading to Astro 7, this is the piece still missing.

    The compatibility-package trap

    Microsoft published @typescript/typescript6 for the interim: it installs TypeScript 6 alongside 7 and exposes a tsc6 binary, so your older tooling keeps its API while the build uses 7.

    It works. But it has an undocumented side effect that leaves you believing you migrated when you did not.

    I installed exactly what the manual says:

    { "devDependencies": { "typescript": "^7.0.2", "@typescript/typescript6": "^6.0.2" } }
    

    Here is what comes out:

    $ npm ls typescript
    └── [email protected]          # says you are on 7
    
    $ npx tsc --version
    Version 6.0.3                 # but your build runs 6
    
    $ node node_modules/typescript/bin/tsc --version
    Version 7.0.2                 # 7 is right there, nobody calls it
    

    The cause is how the compatibility shim is packaged: @typescript/typescript6 depends on "@typescript/old": "npm:typescript@^6" — an alias — and that dependency’s tsc bin wins the node_modules/.bin/tsc link, shadowing TypeScript 7’s own.

    The functional proof, using the same tsconfig with baseUrl in it:

    # npx tsc  (what your build script would call)
    error TS5101: Option 'baseUrl' is deprecated and will stop functioning in TypeScript 7.0.
                  Specify compilerOption '"ignoreDeprecations": "6.0"' to silence this error.
    
    # the real TypeScript 7 binary
    error TS5102: Option 'baseUrl' has been removed. Please remove it from your configuration.
    

    A deprecation warning versus a removal error. If your CI shows TS5101, you are not compiling with TypeScript 7, whatever npm ls and your package.json claim.

    How to be sure which one you run:

    node node_modules/typescript/bin/tsc --version   # always the truth
    npx tsc --version                                # what your build executes
    

    If they disagree, point your scripts at the explicit binary or drop the compatibility package.

    Two small details that bite in CI

    The exit code changed. On type errors, TypeScript 6 exits 2 and TypeScript 7 exits 1. I checked three times in a row and it is deterministic; with no errors both exit 0. If you have a script doing if [ $? -eq 2 ] to tell “there are type errors” from “the compiler crashed”, it silently stops working.

    There is no more tsserver. A clean typescript@7 install leaves only tsc in node_modules/.bin. TypeScript 7 speaks LSP, which is why editors need their own support: VS Code ships an extension and Visual Studio enables it automatically, but anything that spawned tsserver by hand needs review.

    How to adopt it today without breaking anything

    The advice almost nobody is giving properly is that this is not all-or-nothing. You can collect the 11× where it pays and leave the rest alone until 7.1.

    Layer 1 — type checking, right now. A separate script pointing explicitly at the TypeScript 7 binary, for local npm run typecheck and for CI. That is where 11× actually shows, because it is the thing you sit and watch.

    Layer 2 — linter and tests, staying on TypeScript 6. typescript-eslint, ts-jest and anything touching the AST stay on 6 until they ship support for the 7.1 API.

    The least painful order of work:

    1. Clean the tsconfig first, while still on TypeScript 6. Drop baseUrl, move moduleResolution to bundler or nodenext, remove target: es5. All of that is valid in 6, so you can do it and ship it without a major bump. Once it is green, the migration is a version number.
    2. Pin the version. Set "typescript": "6.0.3" exactly, no ^, for the duration. You do not want to discover the change during a Friday npm install.
    3. Try 7 on a branch, with the explicit binary, and diff its error output against 6. They should match; where they do not, that is your real work list.
    4. Wait for 7.1 for the rest. Until the new API exists and tools adopt it, going all in trades 11× of speed for having no linter and no tests.

    Checklist before you bump

    • baseUrl gone, and paths rewritten with a leading ./.
    • moduleResolution set to bundler or nodenext (never node, node10 or classic).
    • module set to esnext or preserve (never amd, umd, systemjs or none).
    • target at ES2015 or above.
    • esModuleInterop, allowSyntheticDefaultImports and alwaysStrict not set to false.
    • Checked whether your stack (Vue, Svelte, MDX, Astro) supports 7 yet.
    • Checked that npx tsc --version matches node node_modules/typescript/bin/tsc --version.
    • Reviewed CI scripts that depend on exit code 2.

    Conclusion

    TypeScript 7 is the best performance upgrade the language has ever had: 11× measured on a small project, half the memory, and not one line of application code changed. That part is real and available today.

    What is not available today is the whole ecosystem. The API lands in 7.1, and until then typescript-eslint, ts-jest and the template type-checkers for Vue, Svelte, MDX and Astro stay on 6.

    So the sensible answer to “should I upgrade?” is: clean your tsconfig now, collect the speed on type checking, and leave the linter and tests where they are. And above all, verify which binary your build actually runs — because the compatibility-package trap leaves plenty of projects that believe they are on TypeScript 7 still compiling with 6.

    Compartir

    Search

    Tags

    Tutorial PHP Laravel AI JavaScript Web Development Best Practices Laravel 13 Migration Tools Security Claude SEO Regular Expressions Text Manipulation