Lesson 26 of 28
The Native TypeScript Compiler
TypeScript 7 ships a compiler rewritten in Go — tsc, tsserver and the language service running native. The type system itself is unchanged; the win is speed.
The tsc you've been running through this entire track is a JavaScript
program running on Node — a compiler for TypeScript, written in
TypeScript, bundled and executed by the V8 engine inside your node
process. That's the only tsc there has been, since TypeScript's earliest
days. TypeScript 7 is where that changes: the compiler, the language
server (tsserver), and the language service that your editor talks to
have all been rewritten in Go and ship as a native binary.
The important thing to get right up front: this is a tooling rewrite, not a type-system rewrite. The code you write, the errors you get, the inference the compiler performs — all of that is the same. The compiler that reads your code just happens to be about ten times faster now.
What stayed the same
Everything in this track so far — basic types, narrowing, generics,
utility types, mapped types, template literal types, strict flags,
satisfies, declaration files — is exactly the same under the native
compiler as under the JS-based one. A program that type-checked under
TypeScript 6 type-checks the same way under TypeScript 7.
That matters enough to be worth stating explicitly, because "rewrite" is a word that normally implies "and you'll have to learn new things." In this case: the rewrite was specifically scoped to keep the type system identical. The point was to make the existing TypeScript fast, not to make a new TypeScript.
The surface area that genuinely changed is small enough to list in one place:
- A handful of compiler-internal APIs used by tooling authors (not by application code).
- A couple of inference edge cases where the old compiler's behaviour was known to be inconsistent and the native compiler's is the one the spec actually describes.
- The exact shape of some diagnostic messages, because the implementer took the opportunity to clean up how errors are phrased.
None of that is work for an app developer to care about. If any of it breaks a project, the fix is the same scale as a TypeScript point release — tighten a corner case, re-run.
What actually got faster, and why
The headline target — repeatedly quoted by the team through the native
compiler's long preview — is roughly 10x. On a large monorepo where
a cold tsc --noEmit used to take two minutes, it's measurable in
seconds. For smaller projects the ratio holds but the absolute wall
clock was already short, so you feel it more in CI fan-out and editor
responsiveness than in a single invocation.
The responsiveness part is the one most worth paying attention to.
tsserver — the long-running language-service process that your editor
queries for hover info, autocomplete, "find references," and the red
squiggles — is subject to the same rewrite, which means hover response,
diagnostics on save, and "go to definition" on a cold file all feel
noticeably faster. In a large project that's the difference between an
editor that keeps up with you and one you learn to work around.
The reason these wins exist, as opposed to being a single clever optimisation, is structural:
- Parallelism. A Go program can use real OS threads to type-check multiple files in parallel. A Node-hosted JS program effectively cannot, except by spawning worker processes with their own startup cost.
- Memory layout. The internal data structures the compiler uses — symbol tables, type caches, the shape of an AST node — can be laid out more tightly in native code than they can as JS objects, which pays off at the scale of a million allocations per compile.
- No JIT warmup. A short-lived
tsc --noEmiton a CI machine used to spend measurable time warming up the V8 JIT before hitting steady state. Native code skips that step entirely, which is disproportionately useful for the "run on every commit" use case.
None of these are tricks. They're consequences of moving off a Node host, which is why the speed-up wasn't realistically extractable from the old implementation.
What your project actually has to do to adopt it
For most projects: upgrade the typescript package, re-run your build.
The compiler reads the same tsconfig.json and emits the same
diagnostics. The editor picks up the new tsserver automatically
through its existing TypeScript integration (VS Code, JetBrains IDEs,
and the common Neovim LSP setups all hand the version-resolution job
to the project's installed typescript).
Two things are worth checking the first time:
// tsconfig.json — unchanged in shape; still the same options
{
"compilerOptions": {
"strict": true,
"module": "esnext",
"moduleResolution": "bundler",
"target": "es2022"
}
}- Any custom tooling that depended on the TypeScript compiler's internal JS APIs (ts-morph, transformers, custom ts-loader plugins) needs to be on a version that's been updated for TS 7. The public, documented APIs are stable; the internals, deliberately, are not.
- CI caches keyed on the TypeScript version will be invalidated on first upgrade. Expect one slow CI run, then a much faster steady state.
The point of calling out these small checks is to be honest about where
the migration is not zero work. Everywhere else, the right expectation
is: same TypeScript, your npm run tsc finishes in a tenth of the
time.
How this changes the shape of a workflow
Speed changes behaviour. Three concrete ways a 10x compiler lands in how a team works:
- Pre-commit type-checking becomes realistic. Running
tsc --noEmitas part of a Husky-style pre-commit hook on a large codebase used to be unacceptable — too slow, too interruptive. At the new speed, it's often fine. - CI gets cheaper and more iterable. A type-check step that was minutes long on every PR becomes seconds. Smaller matrices, more frequent runs, less justification for "we only type-check on main."
- Editor-driven refactors feel different. A "rename symbol" across
thousands of files, a "find all references" through the whole
project, a "check this against the current
tsconfig" — operations that used to take enough time to break your train of thought now finish inside one.
None of that is required. You can adopt the native compiler, change nothing about your workflow, and still get the wall-clock win. The workflow changes are what teams tend to opt into once the cost structure of type-checking actually changes.
What to remember
- TypeScript 7 ships a native compiler:
tsc,tsserver, and the language service are rewritten in Go and run as a native binary. The type system is unchanged. - The target is roughly a 10x speed-up on typical real-world projects; the biggest user-visible wins are in editor responsiveness and in large-project CI.
- The gains are structural — real OS parallelism, tighter memory layout, skipping JIT warmup — not a single optimisation; the old Node-hosted compiler could not realistically have reached the same number.
- Upgrading is mostly a package bump. Watch for custom tooling that depends on internal compiler APIs and for the one-time CI cache invalidation.
- Workflow changes (pre-commit type-check, smaller CI matrices, faster editor refactors) are opt-in consequences of the new cost structure, not mandatory migration steps.
Check yourself
4 questions · pass 3/4 to unlock Upgrading to TypeScript 6 and 7
1.What was rewritten in the move to TypeScript's native compiler?
2.Roughly what order of magnitude of speedup does the native compiler target compared with the previous JS-based
tsc?3.Which of these is the *honest* reason a native binary is faster than the JS-based compiler, more than any single micro-optimization?
4.Your project is still pinned to TypeScript 6 while a library you depend on only publishes types tested on TypeScript 7. What is the realistic expectation?
4 left to answer
Discussion
Sign in to postNo comments yet. Be the first to say something.