TypeScript 7.0: What a 10x Faster Compiler Actually Changes

Title card for the article: TypeScript 7.0

Two minutes. That is roughly how long a full type-check of the VS Code codebase used to take on the TypeScript compiler. On July 8, 2026, Microsoft shipped a version that does the same check in about ten seconds — the same types, the same diagnostics, the same emitted JavaScript, one tenth the wait.

TypeScript 7.0 is not a language update. There is no new syntax to learn and no code to rewrite. It is a complete port of the compiler and language service from TypeScript into Go, and the entire headline is speed: Microsoft reports full-build speedups “typically between 8x and 12x,” with editor operations and memory use improving alongside. For a tool that sits in the inner loop of most of the web’s engineering teams, a 10x change in that loop is a bigger deal than it sounds.

This post is about where that 10x actually comes from, why Microsoft chose Go over the more fashionable options, what the number does and does not cover, and what breaks — because a rewrite of a tool this central is never entirely free.

Executive summary

  • What shipped: TypeScript 7.0 reached general availability on July 8, 2026 (RC on June 18), after a preview period that began when Anders Hejlsberg announced the native port in March 2025. It is a from-scratch reimplementation of the existing compiler in Go, deliberately preserving the same algorithms and type-checking semantics.
  • The core number: Full builds and type-checks run roughly 8x–12x faster. The reference benchmark — type-checking the VS Code codebase — dropped from around two minutes to about ten seconds. Editor project-load time fell about 8x and memory use roughly halved.
  • Why it matters: The compiler and language service sit in the developer inner loop and in CI. Cutting that latency by an order of magnitude changes how large TypeScript codebases feel to work in, and shortens the feedback cycle that everything else depends on.
  • The catch: The stable programmatic API does not ship until 7.1. Tools that drive the compiler through that API — including the type-checking paths for Vue, Svelte, Astro, and MDX — must wait or run in a hybrid setup.
  • The interesting decision: Go, not Rust or C#. The reason is specific and instructive, and it says something real about porting large stateful systems.

Background: why the compiler got slow enough to rewrite

TypeScript launched in 2012. The compiler — tsc — was itself written in TypeScript and run on Node.js, which is an elegant kind of bootstrapping: the tool that checks your JavaScript types is itself checked and compiled by an earlier version of itself, then executed as JavaScript.

That choice was right for a decade. It kept the whole project in one language, made the compiler hackable by the same community that used it, and rode the enormous performance gains of the V8 JavaScript engine for free.

But JavaScript is single-threaded and garbage-collected, and it runs on a virtual machine. For most workloads those properties are invisible. For a program whose entire job is to walk enormous graphs of nodes, allocate millions of small objects, and chase pointers between them — which is exactly what a type-checker does — they become a ceiling. As codebases grew from thousands of files to hundreds of thousands, the single-threaded compiler could not use the other cores sitting idle on every developer’s machine, and JIT warm-up and garbage-collection pauses became a measurable tax.

The symptom every large TypeScript shop knows is the editor pause: you type, and a beat later the red squiggles catch up. That pause is the language service — the same type-checker running inside your editor — falling behind your keystrokes. On a large project, “TypeScript is thinking” became a normal part of the day.

The fix was not a better algorithm. The type-checking semantics were fine. The fix was to run the same algorithms on a runtime that could use all the cores and skip the VM overhead.

What actually shipped

TypeScript 7.0 is a native executable. Instead of shipping JavaScript that Node runs, the typescript package now ships a compiler compiled ahead of time to machine code for your platform. The command is still tsc, the config is still tsconfig.json, the types are still your types, and the emitted JavaScript is byte-for-byte the same as before. From the outside, almost nothing changed. Underneath, everything did.

The internal codename was Project Corsa, and the strategy was deliberately conservative: a port, not a rewrite. The team moved the existing structure file by file out of the JavaScript codebase into Go, keeping the same data structures, the same control flow, and therefore the same behavior. That distinction is the whole reason the migration risk is as low as it is — a port can promise semantic parity in a way a clean-sheet rewrite never can.

  TypeScript 6.x                        TypeScript 7.0
  ──────────────                        ──────────────
  compiler written in TypeScript        compiler written in Go
  emitted to JavaScript                 compiled to native machine code
  run on Node.js (V8)                   run as a native binary
  single-threaded checking              parallel checking across workers
  ~2 min to check VS Code               ~10 s to check VS Code
        │                                     │
        └──────────── same tsconfig ──────────┘
        └──────────── same type rules ────────┘
        └──────────── same emitted JS ────────┘

Where the 10x comes from

There is no single trick. The speedup is the sum of three structural changes, none of which were possible in the old runtime.

1. Native code instead of a JIT. Ahead-of-time compiled Go starts fast and runs at a predictable speed from the first instruction. There is no warm-up period where the JIT is still deciding which functions are hot. For a compiler — which often runs once, does a lot of work, and exits — eliminating warm-up alone is a meaningful win, especially in CI where every job pays the cold-start cost fresh.

2. Shared-memory concurrency. This is the largest single contributor. The old compiler was single-threaded; the native one parses, type-checks, and emits in parallel across multiple workers, and those workers share memory rather than copying data between isolated processes. Hejlsberg has pointed to native code with shared-memory concurrency as the specific place the 10x came from. Type-checking is unusually amenable to this because much of the per-file work is independent once the global symbol table is built.

The parallelism is tunable rather than magic:

FlagPurposeDefault
--checkersNumber of parallel type-checking workers4
--buildersParallel workers for project-reference builds
--singleThreadedDisable parallelism (useful for debugging/CI reproducibility)off

Because the work scales across cores, the speedup tends to grow with codebase size rather than staying flat — a large monorepo has more independent work to spread across workers than a single small package.

3. Lower memory and allocation overhead. Go gives fine control over data layout — structs laid out contiguously instead of scattered heap objects — which means less pointer-chasing and less pressure on the garbage collector. In Microsoft’s measurements memory use is roughly half the old implementation, and lower allocation churn directly reduces GC pause time, which was part of the old tax.

  A type-check, conceptually

  parse files ──►  build symbols ──►  check types ──►  emit JS
   (parallel)       (shared            (parallel,        (parallel)
                     memory)            per-file)

  Old: one thread walks this whole pipeline, warming up a JIT,
       allocating churn for the GC, using one core of eight.

  New: native code, workers fan out across cores on the
       independent stages, sharing one symbol table in memory.

The benchmarks, with the caveats attached

Numbers first, context second. These are the figures Microsoft and early adopters have reported:

CodebaseApprox. sizeBeforeAfterSpeedup
VS Code1.5M LOC77.8 s7.5 s~10.4x
Playwright356K LOC11.1 s1.1 s~10.1x
TypeORM270K LOC17.5 s1.3 s~13.5x
date-fns104K LOC6.5 s0.7 s~9.5x

Editor project-load time in the VS Code measurement dropped from roughly 9.6 seconds to 1.2 seconds — about 8x — with memory use roughly halved. Later default-settings runs of the VS Code check have been reported around 11.9x. Early corporate adopters including Bloomberg, Figma, and Notion reported speedups in the same ballpark, and Slack reported cutting a CI type-check from about 7.5 minutes to 1.25 minutes.

Now the caveats, because they determine whether this changes your day:

  • This is the type-check-and-emit step only. TypeScript compiles to the same JavaScript as before, so your runtime is unchanged. Your app is not 10x faster for users.
  • It is not your whole build. If your CI time is dominated by a bundler (webpack, Vite’s Rollup step), a test runner (Jest, Vitest), or Docker layers, a 10x-faster tsc shrinks only its slice. Measure where your time actually goes before expecting your pipeline to shrink 10x.
  • Small projects gain less in absolute terms. Going from 0.6 s to 0.1 s is a 6x speedup you will barely feel. The order-of-magnitude wins are concentrated in the large codebases that were hurting most — which is the right place for them to be, but it means the headline understates the benefit for big teams and overstates it for small ones.

Why Go, and not Rust or C#

This was the most litigated part of the announcement, and the reasoning is worth understanding because it generalizes to any large stateful system.

A type-checker’s central data structures — the abstract syntax tree, the symbol table, the type graph — are dense with cyclic references. Nodes point at their parents; types reference other types that reference back. This is not incidental; it is the natural shape of the problem.

Rust was the fashionable choice, and it was passed over precisely because of its greatest strength. Rust’s ownership and borrow checker is designed to make aliasing explicit and to prohibit the kind of freeform cyclic references the compiler is built on. Expressing a graph full of back-references in safe Rust means reaching for reference-counted pointers, arena allocators, or index-based indirection throughout — which is not a translation of the existing code, it is a redesign of its core data model. That is a multi-year project, and worse, it breaks the one promise that made this migration acceptable: identical type-checking semantics. Rust would have produced a different compiler that happens to check TypeScript, not a faithful port of the one that exists.

C# — Microsoft’s own language, and Hejlsberg’s own creation — was passed over for more prosaic reasons. It is bytecode-first rather than native on every platform out of the box, and it is heavily object-oriented, whereas the TypeScript compiler is written in a functions-and-data-structures style. Hejlsberg characterized Go as roughly the lowest-level language they could target that still delivered native code on all platforms, good control over data layout, and unrestricted cyclic data structures.

Go fit the actual constraints:

RequirementRustC#Go
Cyclic data structures without redesignFights itYesYes
Garbage collected (matches old compiler)NoYesYes
Native code on all platformsYesNot by defaultYes
Function-and-data style matches existing codePartialOO-firstYes
Port feasible in ~1 year with same semanticsNoMaybeYes

The through-line: both the old and new compilers rely on garbage collection, and both are written in a function-heavy style, so the code ported almost one-to-one. Go was not chosen because it is the fastest possible language in the abstract. It was chosen because it was the fastest language they could reach while keeping the port a port. That is a pragmatic engineering call, not an ideological one, and it is the reason the release could promise semantic parity at all.

What breaks, and who should wait

A port preserves type-checking behavior, so the code you already have should check the same way. The friction lives in the ecosystem around the compiler.

The single most important limitation: the stable programmatic API does not ship until TypeScript 7.1. The old compiler exposed a rich JavaScript API that a large tooling ecosystem drives directly, and reproducing that surface on a native binary is its own project. Until it lands, anything that imports the TypeScript API and calls into the compiler programmatically is affected.

  Safe to adopt now                 Wait for 7.1 (or run hybrid)
  ─────────────────                 ────────────────────────────
  tsc on the command line           Vue type-checking (vue-tsc)
  npm scripts that call tsc         Svelte / Astro / MDX checking
  most apps and libraries           Tools importing the TS API
  editor language service           Custom compiler-plugin toolchains
  CI type-check jobs                Anything driving tsc via the API

If you ship a plain TypeScript app or library, none of this touches you and you can try 7.0 in a branch today. If you build with a framework whose type-checking rides the programmatic API — Vue, Svelte, Astro, MDX — the type-checking half of that tooling has to wait for the API to stabilize, even though the rest of your stack can move.

There is also configuration cleanup along the 6.x-to-7.0 line: some legacy module formats and old compilation targets have been retired, and the watch implementation was rebuilt on a native file-watcher. A tsconfig that still targets very old runtimes or emits legacy module systems may need updating. None of this is exotic, but it is worth checking before assuming a zero-diff upgrade.

How to migrate without drama

The safe pattern is not a hard cutover. It is a parallel run:

  1. Install the native compiler in a branch.
       npm install -D typescript@7

  2. Run BOTH compilers on your real codebase.
       tsc --noEmit           # native
       (compare against your current 6.x diagnostics)

  3. Treat every diagnostic difference as a bug to investigate,
     not as noise to ignore. Semantic parity is the promise;
     a real difference is worth a report.

  4. Flip your CI type-check to native once it is green.
     Keep the old path for any API-dependent tool until 7.1.

  5. Tune --checkers to your CI machine's core count if the
     default of 4 leaves cores idle.

The reason to compare diagnostics rather than trust them blindly is that “should be identical” and “is identical on your specific code” are different claims. The port is careful, but your codebase may exercise a corner the benchmarks did not. A parallel run turns that risk into a checklist item instead of a production surprise.

The wider pattern: native rewrites of JavaScript tooling

TypeScript 7.0 is the most prominent example of a trend that has been building for years: the JavaScript ecosystem is rewriting its own tooling in native, multi-threaded languages, and the JavaScript-authored generation is being retired.

ToolOld (JS/TS)Native replacementLanguage
Compilertsc (TypeScript)tsc 7.0Go
Bundlerwebpackesbuild / TurbopackGo / Rust
LinterESLintBiome / OxcRust
FormatterPrettierBiomeRust
Package toolingnpmBunZig

The pattern is consistent: the JavaScript-authored generation optimized for hackability and a single-language stack; the native generation optimizes for throughput on codebases that outgrew the old assumptions. TypeScript is the most conservative entry on this list — it chose a port over a rewrite specifically to keep semantics stable — but it is the same current. When the team behind the language itself concludes the compiler belongs in native code, it is a strong signal about where the ecosystem’s performance floor is heading.

The counter-current worth noting: the native-tooling wave fragments the ecosystem’s shared foundation. When every tool was JavaScript importing the TypeScript API, a plugin written once worked everywhere. Native tools each expose their own interfaces, and the 7.1 API gap is a small preview of the coordination cost that comes with the speed.

Practical takeaways

  • If you run a large TypeScript codebase, this is the highest-leverage free upgrade available right now. The inner-loop and CI latency you have been treating as a fixed cost is not fixed anymore.
  • Measure your build before you celebrate. The 10x is on tsc, not on your bundler or tests. Profile your pipeline so your expectations match your actual bottleneck.
  • Adopt via parallel run, not hard cutover. Compare diagnostics between the old and new compiler on your real code; flip only when they match.
  • Check your framework tooling first. Vue, Svelte, Astro, and MDX type-checking depend on the programmatic API arriving in 7.1. Plan a hybrid setup or wait.
  • Tune parallelism to your hardware. The default of four checker workers may leave cores idle on a big CI machine; --checkers is the knob.

Future predictions (clearly marked as predictions)

These are informed extrapolations, not established facts.

  • 7.1 will be the release most teams actually standardize on. The stable programmatic API is the gate for the framework and tooling ecosystem, and a large share of real-world projects touch it indirectly. Expect the framework-heavy half of the community to treat 7.1, not 7.0, as their “safe to adopt” line.
  • The native-tooling consolidation accelerates. With the language’s own team validating a native compiler, expect more of the JavaScript build stack — remaining linters, test runners, type-aware build-time tools — to follow, and expect at least one attempt to unify them behind a shared native core to reduce the plugin fragmentation.
  • The felt win will be the editor, not CI. CI speedups are easy to headline, but sub-second completions and instant go-to-definition on codebases that used to stall are what developers will actually notice day to day. That is a prediction about perception, and perception is where tool loyalty is decided.

Conclusion

TypeScript 7.0 is a rare kind of release: a change that is simultaneously enormous and invisible. Enormous, because it moves the compiler that most of the web’s type-checked code depends on from a single-threaded JavaScript program into parallel native code, and cuts an order of magnitude off the inner loop. Invisible, because it was engineered as a port precisely so that your types, your config, and your emitted JavaScript stay exactly as they were.

The engineering lesson underneath is the one worth keeping. The team did not chase the fastest possible language or the most fashionable one. They chose the language that let them keep the migration a faithful port — cyclic data structures intact, garbage collection intact, function-heavy style intact — because semantic parity was worth more than a few percent of theoretical peak speed. For a tool this central, “10x faster and behaves identically” is a far stronger promise than “20x faster and subtly different,” and the whole release is organized around that trade.

If you maintain a large TypeScript project, the practical instruction is short: run the native compiler alongside your current one this week, compare the output, and let the numbers decide. The upgrade is free, the risk is measurable, and the two minutes you used to spend waiting for a type-check is the kind of cost you only notice once it is gone.

FAQ

References and further reading

Benchmark figures in this article are as reported by Microsoft and early adopters; results vary by codebase, configuration, and hardware. Sections marked as predictions are analysis, not established fact.

Next: Your LLM Cost Model Is Linear. Your Agent Is Not.