Skip to content

Commit 63f7396

Browse files
ankur-archclaude
andauthored
feat(blog): TypeScript 7 native compiler performance post (#8047)
* feat(blog): add TypeScript 7 native compiler performance post Adds a succinct post on migrating a large TypeScript monorepo to the TypeScript 7 native (Go) compiler, cutting whole-repo type checking to roughly a third of the time. Authors: Ankur Datta, Sampo Lahtinen. Includes a simple on-brand hero/meta cover. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blog): rework TS7 post for readability, add benchmarks, code, new cover - Restructure into numbers table, migration checklist, config/code diffs, sharp edges, what-didn't-improve, and a should-you-migrate decision block. - Add show-don't-tell snippets (baseUrl diff, compiler-API before/after, typed-array + Buffer fixes, heap-flag removal, install command). - Tighten the Prisma tie-in to a narrow generated-types argument. - Redesign cover in the Rust-migration style: navy + TypeScript blue, TS mark paired with the Prisma wordmark, and a before/after 74s->24s bar chart. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blog): lighten prose in TS7 post for readability Tighten and de-jargon the prose throughout without dropping information: punchier lead, clearer numbers caveat, simpler section transitions. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(blog): apply TS7 post review feedback Address reviewer comments (ankur-arch + CodeRabbit): - Trim redundant wording; accept fluency suggestions in the lead, the "what it is", "what improved", and heading sections. - Make the benchmark reproducible: pin TS versions (5.8.2 -> 7.0.2), note warm cache and median-of-several-runs on GitHub Actions. - Separate TS 6-era config prerequisites (baseUrl/rootDir/types) from the native-port work so failures aren't blamed on the Go compiler. - Pin vite-tsconfig-paths floor to v5.1.4+; clarify the rawKey cast assumes a plain ArrayBuffer. - Add an editor/framework caveat (Vue, Svelte, Astro, MDX) to "wait a bit". - Use pnpm and a pinned version for the trial install. - Drop the off-topic Prisma Next tie-in; close with an honest Prisma Console note and a non-salesy pris.ly/pdp CTA. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 7ed0d25 commit 63f7396

3 files changed

Lines changed: 261 additions & 0 deletions

File tree

  • apps/blog
    • content/blog/typescript-7-native-compiler-faster-type-checking
    • public/typescript-7-native-compiler-faster-type-checking/imgs
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
---
2+
title: "TypeScript 7 in a Real Monorepo: 3x Faster Type Checks, Mostly Config Changes"
3+
slug: "typescript-7-native-compiler-faster-type-checking"
4+
date: "2026-07-09"
5+
authors:
6+
- "Ankur Datta"
7+
- "Sampo Lahtinen"
8+
metaTitle: "TypeScript 7 Native Compiler: 3x Faster Type Checks in a Real Monorepo"
9+
metaDescription: "TypeScript 7 ships the compiler as a native Go port. We migrated a large TypeScript monorepo to it: whole-repo type checking went from ~74s to ~24s with no memory tuning. Here are the numbers, the exact config diffs, the sharp edges, and who should migrate now."
10+
metaImagePath: "/typescript-7-native-compiler-faster-type-checking/imgs/meta.png"
11+
heroImagePath: "/typescript-7-native-compiler-faster-type-checking/imgs/hero.svg"
12+
heroImageAlt: "Headline 'Type checking, 3x faster' beside a before/after bar chart: a tall slate bar labeled TS 5.x at 74 seconds and a short glowing blue bar labeled TS 7 at 24 seconds, with a '3x faster' callout. TypeScript logo top-left, Prisma wordmark top-right."
13+
tags:
14+
- "education"
15+
- "platform"
16+
---
17+
18+
TypeScript 7 is [out](https://devblogs.microsoft.com/typescript/announcing-typescript-7-0/). Microsoft rewrote the compiler in Go and measures it at roughly 10x faster than the old JavaScript one. We moved a large monorepo onto it the day it shipped. Whole-repo type checking dropped from about 74 seconds to about 24 seconds, and we deleted the memory flags CI needed to finish the job.
19+
20+
Here are the numbers, what we changed, what broke, and how to decide whether to migrate now.
21+
22+
## The numbers
23+
24+
One monorepo, dozens of packages and apps, checked with a single unchanged `pnpm typecheck` command. The figures below are the median of several GitHub Actions runs on each compiler, with a warm dependency cache.
25+
26+
| Metric | Before (TS 5.x) | After (TS 7) | Change |
27+
| --------------------- | ------------------- | ------------- | ------------- |
28+
| TypeScript version | 5.8.2 | 7.0.2 ||
29+
| Whole-repo type check | ~74s | ~24s | ~3x faster |
30+
| Node heap flag | up to 8 GB | none | removed |
31+
| Command | `pnpm typecheck` | unchanged | unchanged |
32+
| CI runner | GitHub Actions | unchanged | unchanged |
33+
34+
We got 3x, not the 10x from Microsoft's [benchmarks](https://devblogs.microsoft.com/typescript/announcing-typescript-7-0/). The reason is simple: only part of our CI time was ever spent in `tsc`. The rest goes to bundling, tests, and code generation, and the new compiler touches none of that. Your number will land somewhere else again, depending on how type-heavy your code is. The speedup is real; the exact multiplier is yours to measure.
35+
36+
## What TypeScript 7 actually is
37+
38+
Same TypeScript with a faster engine. The syntax, type rules, and error messages are the same. The old compiler ran as single-threaded JavaScript; the new one runs as native, parallel Go. That is the whole source of the speedup, and it is why migrating is a tooling-and-config job rather than a code rewrite.
39+
40+
## What we had to change
41+
42+
Almost none of it touched application code. Here's the checklist we followed, ordered so the nastiest surprises come last.
43+
44+
1. Run your existing type check on the classic compiler first, so a later failure means a real problem, not a migration artifact.
45+
2. Move to a single compiler version across the repo.
46+
3. Update `tsconfig` path resolution (remove `baseUrl`).
47+
4. Replace any code that imports `typescript` as a library.
48+
5. Fix the handful of type-level differences.
49+
6. Lock the version and compare timings.
50+
51+
The two that produce real diffs are worth showing.
52+
53+
### Remove `baseUrl` from tsconfig
54+
55+
TypeScript 7 resolves `paths` relative to the config file. So `baseUrl` goes away, and each alias becomes an explicit relative path instead. Same result, one fewer moving part.
56+
57+
```diff
58+
{
59+
"compilerOptions": {
60+
- "baseUrl": ".",
61+
"paths": {
62+
- "@/*": ["src/*"]
63+
+ "@/*": ["./src/*"]
64+
}
65+
}
66+
}
67+
```
68+
69+
If you use `vite-tsconfig-paths`, upgrade it to v5.1.4 or newer at the same time. Older versions relied on `baseUrl` to anchor aliases and will break the production build without it.
70+
71+
Keep one thing straight here: dropping `baseUrl` is a configuration change, not a Go-compiler one. The same goes for `rootDir` now defaulting to the `tsconfig.json` directory and `types` no longer auto-loading every `@types` package. If one of these bites you, it's a config prerequisite to fix, not the native compiler misbehaving.
72+
73+
### Stop importing the compiler as a library
74+
75+
This is the one people miss. TypeScript 7 does **not** ship the programmatic compiler API yet. Microsoft expects it in 7.1 and, until then, recommends keeping classic TypeScript installed alongside it for tools that need it. So any script that does `import ts from "typescript"` to walk the AST needs a plan.
76+
77+
We had one such script that read component props out of `.tsx` files:
78+
79+
```ts
80+
// Before: uses the TypeScript compiler API (unavailable in TS 7)
81+
import ts from "typescript";
82+
83+
const source = ts.createSourceFile(file, src, ts.ScriptTarget.Latest, true);
84+
for (const node of source.statements) {
85+
if (ts.isInterfaceDeclaration(node)) {
86+
// ...read members
87+
}
88+
}
89+
```
90+
91+
We moved it to a standalone parser that has no dependency on the compiler:
92+
93+
```ts
94+
// After: uses oxc-parser, which emits a plain ESTree AST
95+
import { parseSync } from "oxc-parser";
96+
97+
const { program } = parseSync(file, src);
98+
for (const node of program.body) {
99+
if (node.type === "TSInterfaceDeclaration") {
100+
// ...read members
101+
}
102+
}
103+
```
104+
105+
The regenerated output was byte-for-byte identical. If you can't drop the compiler API, pin classic TypeScript in the one package that needs it:
106+
107+
```jsonc
108+
// repo default: the native compiler
109+
"typescript": "7.0.2"
110+
111+
// only in the package that still needs the compiler API:
112+
"typescript": "5.8.2"
113+
```
114+
115+
## Sharp edges
116+
117+
A short list of differences the native compiler flagged. Every one was type-only; nothing changed at runtime.
118+
119+
- **Typed-array generics are stricter.** WebCrypto and `node:crypto` calls now want an explicit `ArrayBuffer` type argument.
120+
121+
```diff
122+
- crypto.subtle.importKey("raw", rawKey, { name: "AES-GCM" }, true, ["encrypt"]);
123+
+ crypto.subtle.importKey("raw", rawKey as Uint8Array<ArrayBuffer>, { name: "AES-GCM" }, true, ["encrypt"]);
124+
```
125+
126+
The cast assumes `rawKey` is backed by a plain `ArrayBuffer`. If it can be a `SharedArrayBuffer`, copy the bytes into a fresh `Uint8Array` instead of asserting the type.
127+
128+
- **`Buffer` no longer satisfies a `Uint8Array` type.** Test fixtures that leaned on `Buffer` had to be built as real typed arrays.
129+
130+
```diff
131+
- const bytes = Buffer.from([1, 2, 3]);
132+
+ const bytes = new Uint8Array([1, 2, 3]);
133+
```
134+
135+
- **Deep recursive mapped types can hit a recursion limit** the old compiler let slide. We rewrote one into an equivalent non-recursive form.
136+
137+
- **The memory flags are gone.** The native compiler holds far less in memory, so the heap tuning we'd piled up to keep CI green is no longer needed.
138+
139+
```diff
140+
- "typecheck": "NODE_OPTIONS=--max-old-space-size=8192 tsc --noEmit",
141+
+ "typecheck": "tsc --noEmit",
142+
```
143+
144+
## What improved, and what did not
145+
146+
The win was that the type check got faster and lighter, and editors stay responsive on large projects because the language service ships in the same native port.
147+
148+
What it did **not** change matters just as much:
149+
150+
- Bundling and the production build are no faster. Those run through Vite and esbuild, and `tsc` emits nothing in our setup.
151+
- Nothing changed at runtime, every fix above was type-level.
152+
- Type-level bottlenecks are still bottlenecks. A pathological type is still slow, now slow in Go.
153+
- Compiler-API tooling is still your problem, until the 7.1 API lands.
154+
- Generated types are no smaller.
155+
156+
## Should you migrate to TypeScript v7 now?
157+
158+
**Try it now if:**
159+
160+
- Type checking is a meaningful slice of your CI time.
161+
- Your editor slows down on a large project.
162+
- Your repo doesn't depend on the compiler API.
163+
- You can run it in CI before making it the default.
164+
165+
**Wait a bit if:**
166+
167+
- Your tooling imports `typescript` as a library.
168+
- You rely on custom AST transforms or compiler-API scripts.
169+
- Your editor or framework tooling isn't ready yet. Vue, Svelte, Astro, and MDX still lean on the classic language service, so you may want to type-check with TypeScript 7 on the CLI while keeping the classic TypeScript for IDE support.
170+
- Bundling, tests, or code generation dominate your build, not type checking.
171+
172+
Trialing it is low-risk. TypeScript 7 installs as the normal package, so you can point one CI job at it and keep the old compiler a command away.
173+
174+
```bash
175+
pnpm add -D typescript@7.0.2
176+
```
177+
178+
## The takeaway
179+
180+
The speedup is real, and the migration is mostly config. The monorepo we moved is Prisma Console itself, so we feel the tighter type check on every push. Point your own type check at TypeScript 7, compare the numbers, and commit if they hold.
181+
182+
You can try the Prisma platform we build this way at [pris.ly/pdp](https://pris.ly/pdp).

apps/blog/public/typescript-7-native-compiler-faster-type-checking/imgs/hero.svg

Lines changed: 79 additions & 0 deletions
Loading
418 KB
Loading

0 commit comments

Comments
 (0)