
Why TypeScript 7's VS Code Benchmark Won't Predict Your CI Build Times
On this page
Introduction
A report attributed to tech-insider.org — dated 2026-11-03 in the feed where I found it — claims TypeScript 7 builds VS Code 11.9x faster than TypeScript 6. The framing: compiler performance is the headline theme of the next major release.
Where I come out up front: the number is almost certainly a real measurement of something, and a speedup that large has a plausible mechanism. But it's a compiler-throughput result on one codebase, and the material I have doesn't spell out the conditions. It is not a forecast for your CI pipeline. Plan a migration around "our builds get 10x faster" and you get to explain to your manager why the pipeline only got 40% faster.
This post separates what the report says from what it leaves out, walks through where a speedup of that size actually comes from architecturally, and builds the harness to answer the only question that matters: how much of your wall clock is tsc? By the end you'll have reproducible commands, a projection table for your own build times, and a checklist for deciding whether a TypeScript 7 migration is worth it in your repo.
What the TypeScript 7 Benchmark Report Claims, and What It Leaves Out
The single number — an 11.9x VS Code build
The report compares TypeScript 7 against TypeScript 6 and reports an 11.9x faster build of VS Code. That is the entirety of the technical claim I have: one multiplier, one codebase, two compiler generations. I haven't reproduced it and won't pretend otherwise.
What a benchmark like this needs before you can plan against it:
| What you need to know | Why it changes the answer |
|---|---|
| CPU model and core count | A parallel compiler on 2 vCPUs is a different product than on 16 |
| Exact compiler versions | "TypeScript 6" and "TypeScript 7" are moving targets |
| The exact command | tsc -b on a project-reference graph ≠ tsc --noEmit on one config |
| Cache state | Cold .tsbuildinfo vs warm changes the ratio dramatically |
| Scope | Type-check only, or the entire VS Code product build including bundling? |
| Run count and variance | One run is an anecdote; p50 and p95 are data |
The feed material contains none of it. Treat 11.9x as a signal that the compiler got a lot faster, not as an input to a capacity plan.
Confirmed, inferred, and still unknown
Confirmed by the source: the report exists, it is attributed to tech-insider.org with the date above, and it states the 11.9x figure for a VS Code build comparing TypeScript 7 to TypeScript 6.
Confirmed by a primary source: the TypeScript team has publicly described a native port of the compiler, written in Go, aimed at roughly an order of magnitude in build and editor performance, with the VS Code codebase as its worked example. That is Anders Hejlsberg's March 2025 post, A 10x Faster TypeScript. Per that post, the native compiler lands at TypeScript 7, with a JavaScript-based 6.x line continuing alongside it for compatibility. Plans shift, so check the current release notes before you depend on the version numbering.
Inferred, not stated by the source: the 11.9x likely measures the native compiler building the program and type-checking the VS Code source tree, not the full product build, which includes extension bundling, webview builds, and other tooling. If that inference holds, the number is a compiler number wearing a build number's clothes.
Unknown: hardware, core count, compiler flags, cache state, run count, and which TypeScript 6 build formed the baseline. Unknown means unknown, not "probably the same as other benchmarks."
Where a Large Compiler Speedup Actually Comes From
The architectural shift behind the claim
Today's compiler is JavaScript on a single thread. Every cold process pays JIT warm-up; every run allocates an enormous graph of nodes, symbols, and types into one heap and collects garbage over it while checking. Those costs aren't incidental — on a codebase the size of VS Code they're a large share of total time.
The native port changes the cost model instead of micro-optimizing it. Go is compiled ahead of time, so there's no JIT warm-up. Goroutines share memory rather than serializing through a message channel, so per-file work — parsing, binding, emitting — can run in parallel across cores. The team's own framing includes memory use and editor responsiveness, not just throughput: a smaller, more predictable heap is what keeps the language service responsive on huge projects.
Which compiler phases get faster, and which barely move
A headline multiplier never transfers cleanly because not every phase parallelizes. What follows is my reasoning from how the compiler is structured, not a published phase breakdown — treat it as a model to test, not a fact:
| Phase | Parallelizes? | Why |
|---|---|---|
| Parse | Yes, cleanly | Purely per-file, no cross-file state |
| Bind | Yes, cleanly | Symbol tables are per-file before merging |
| Module resolution / file I/O | Partly | I/O-bound; concurrency helps, disk does not |
| Check | Poorly | Assignability, inference, and declaration merging are cross-file and order-sensitive |
| Emit | Yes, cleanly | Per-file output |
| Declaration emit | Partly | Type printing pulls on global state |
Check time is usually the biggest line item on real projects, and it's the phase where parallelism buys the least. That's the structural reason an 11.9x compiler does not become an 11.9x build: the workload you care about most is the one that resists the optimization most.
Run npx tsc -p tsconfig.json --extendedDiagnostics on your own repo. The Check time line against Total time tells you what fraction of your compile sits in the phase that parallelizes worst. That ratio predicts your realistic gain better than any external benchmark.
Amdahl's law inside your own pipeline
The arithmetic that decides your outcome is Amdahl's law. If tsc is a fraction p of your pipeline and gets s times faster, your pipeline speedup is:
speedup = 1 / ((1 - p) + p / s)
With s = 11.9, that gives you the table below. These are computed values, not measurements:
tsc share of pipeline (p) | Projected pipeline speedup | Ceiling at infinite speedup |
|---|---|---|
| 10% | 1.10x | 1.11x |
| 25% | 1.30x | 1.33x |
| 50% | 1.85x | 2.00x |
| 75% | 3.19x | 4.00x |
| 90% | 5.69x | 10.00x |
Look at the last column. Even if the new compiler took zero seconds, a pipeline where type-checking is 25% of wall clock gets 1.33x faster overall. That's the real decision boundary — which is why the first move is not to upgrade. It is to measure.
Why Your CI Wall Clock Will Not Drop 11.9x
Cold caches, shared vCPUs, and container overhead
Your CI runner starts cold. No .tsbuildinfo, no page cache warmed by the previous run, no warm module graph. It's also usually a shared VM with 2–4 vCPUs, so the new parallel compiler has fewer cores to spread across than the laptop where the benchmark ran. On top of that, a container's overlay filesystem adds I/O latency that a per-file parallel design can amplify — many goroutines hitting slow storage at once isn't always faster than one thread hitting it in sequence.
Everything in CI that is not tsc
Here's a typical frontend CI job. The shares are illustrative — replace them with your own phase-timer output:
| Stage | Illustrative share | Moves with a faster compiler? |
|---|---|---|
| Checkout | 5% | No |
npm ci | 25% | No |
| Codegen (GraphQL, protobuf) | 8% | No |
| Type-check | 22% | Yes |
| Bundling | 20% | No |
| Tests | 17% | Partly — if your test runner transpiles via the compiler |
| Artifact upload | 3% | No |
Two rows change. Five don't. That table is the whole argument, and you can build your own version in about twenty minutes.
The difference between a warm editor and a cold runner
In the editor, the language service keeps a program in memory and patches it as you type. In CI, every run rebuilds the world from scratch. The --incremental and -b machinery exists to close that gap, but only if the build info survives between runs:
## Persist type-check state across CI runs.
## The key must include every input that affects the program,
## or you will reuse a stale graph and get wrong results.
- uses: actions/cache@v4
with:
path: "**/*.tsbuildinfo"
key: tsc-${{ runner.os }}-${{ hashFiles('**/package-lock.json', '**/tsconfig*.json', '**/*.ts', '**/*.tsx') }}
Look at the last two hash inputs. Leave source files out of the key and you hit the classic bug: a cache hit, a stale .tsbuildinfo, and a build that skips type-checking files you just changed. Include them and the cache will almost never hit — which tells you something honest. Cross-commit incremental builds are harder than they look.
Building a Timing Harness You Can Trust
Capture a baseline on your own hardware first
Pin the environment so the numbers mean something:
node -v && npm -v && npx tsc -v
lscpu | grep -E 'Model name|^CPU\(s\)' # or: sysctl -n machdep.cpu.brand_string
Then measure the compiler alone, split into cold and warm, with hyperfine:
#!/usr/bin/env bash
set -euo pipefail
RUNS=${RUNS:-7}
## COLD: delete every build-info file before each run
hyperfine --warmup 1 --runs "$RUNS" --prepare 'find . -name "*.tsbuildinfo" -not -path "*/node_modules/*" -delete' --export-json tsc-cold.json 'npx tsc -b'
## WARM: reuse whatever the previous run produced
hyperfine --warmup 1 --runs "$RUNS" --export-json tsc-warm.json 'npx tsc -b'Run it twice — once on TypeScript 6, once on TypeScript 7 — with the same node_modules resolution, the same flags, nothing else changed. Change the compiler and the bundler in the same commit and you have measured nothing useful.
Isolating type-check time from install, bundle, and test
You need the phase split, not just the total. This wrapper times each stage and emits JSON you can diff across compiler versions:
import { spawnSync } from "node:child_process";
// Adjust the commands to your repo; keep them identical across runs.
const phases = [
["install", "npm ci --prefer-offline --no-audit --no-fund"],
["typecheck", "npx tsc -b"],
["bundle", "npx vite build"],
["test", "npx vitest run --reporter=dot"],
];
const timings = {};
for (const [name, cmd] of phases) {
const start = performance.now();
const result = spawnSync(cmd, { shell: true, stdio: "inherit" });
if (result.status !== 0) {
console.error("phase failed:", name, "exit", result.status);
process.exit(result.status ?? 1);
}
timings[name] = Number(((performance.now() - start) / 1000).toFixed(2));
}
const total = Object.values(timings).reduce((a, b) => a + b, 0);
console.log(JSON.stringify({ timings, total, at: new Date().toISOString() }, null, 2));The number you want is timings.typecheck / total. That ratio is p in the table above, and it's the only thing between the benchmark report and your reality.
For a finer split inside the type-checker itself, --extendedDiagnostics breaks the work into Parse time, Bind time, Check time, Emit time, and Total time, plus workload counters like Types and Instantiations. The counters matter more than the timings across compiler generations: millions of Instantiations means your bottleneck is generic inference in your own code, and no compiler upgrade fixes a type-level utility that expands exponentially.
Reporting p50 and p95 instead of one lucky run
A single CI number is a coin flip. Pull percentiles out of hyperfine's times array:
jq -r '
.results[0] as $r
| ($r.times | sort) as $t
| ($t | length) as $n
| "median=\($r.median)s",
"p95=\($t[((($n - 1) * 0.95) | floor)])s",
"max=\($r.max)s"
' tsc-cold.json
Report p50 for the typical developer experience and p95 for the CI you actually pay for. If p95 is 3x p50, your problem is runner variance, not the compiler — fix that before benchmarking anything else.
Editor Feedback Is a Separate Benchmark
Project load, check time, and the language service
Editor responsiveness is a different workload: incremental, warm, interactive. In VS Code, run TypeScript: Open TS Server Log and read the project-load and check entries. The format drifts between versions, so read the surrounding lines instead of pattern-matching one string. You want to know which dominates: project load (big include globs, a large node_modules type surface) or check time (actual type complexity).
A native compiler that removes JIT warm-up should help cold start the most — exactly the first-open-a-big-repo experience. That's an inference from the architecture, not something I measured.
Watch mode, incremental state, and .tsbuildinfo reuse
tsc -b --watch is where incremental state pays off and where it also bites. Two rules that keep you out of trouble:
- Never share a
.tsbuildinfobetween differenttsconfigfiles or differentoutDirsettings. SettsBuildInfoFileexplicitly in composite projects. - If a build ever behaves as if a file didn't change,
--forceontsc -bis the diagnostic, not the fix. A stale build-info file that outlives a config change is a correctness bug, not a performance feature.
Downstream tools that embed the compiler
This is the migration risk almost nobody budgets for. These tools don't shell out to tsc — they import the compiler and drive its API:
- typescript-eslint — type-aware lint rules need a
Program - ts-node and ts-jest — compile-on-require
ts-morph, customts.TransformerFactorytransforms,api-extractor,fork-ts-checker-webpack-plugin
If the new compiler is a separate implementation, the JavaScript API surface those tools call becomes a compatibility boundary that has to be bridged. I don't know the state of that bridge for TypeScript 7. The public plan describes API compatibility work, but the details and completeness are something to verify against the release notes for the version you adopt — not to take from a blog post. Including this one.
Migration Risks Worth Budgeting For
Tools pinned to the compiler API surface
Audit before you upgrade, not after:
## Anything that pulls in the compiler as a library rather than a CLI
npm ls typescript
grep -rn "from \"typescript\"\|require(\"typescript\")" --include="*.ts" --include="*.js" \
--exclude-dir=node_modules .
Every hit is a place to re-validate. Deep imports into typescript/lib/* are the highest-risk category because they aren't a supported API at all.
Config and flag drift between compiler generations
Major compiler generations deprecate flags, change defaults, and tighten checks. I'm deliberately not listing specific removals — I don't have a verified list for this release, and guessing at config migrations is how people lose a day. Use tsc --showConfig to dump the effective configuration under each compiler and diff them:
npx tsc --showConfig > config-ts6.json
npx tsc --showConfig > config-ts7.json
diff config-ts6.json config-ts7.json
That diff is your actual migration checklist, generated instead of assumed.
A staged rollout order that keeps main green
- Measure first. Run
phase-timeron the current compiler. Iftypecheck / totalis under ~0.25, stop — the migration isn't worth it yet. - Branch, don't flip. Build a branch with the new compiler and run the full test suite plus a clean
tsc -b. - Dual-run in CI for a week. Keep both compilers running on every PR so drift shows up as a red job, not as a surprise at merge time:
## Substitute the real published versions you are comparing.
strategy:
matrix:
ts: ["<current>", "<next>"]
steps:
- run: npm i -D typescript@${{ matrix.ts }}
- run: npx tsc -b --force
- run: npm test
- Flip the default, keep the old job non-blocking for another week so you can attribute failures.
- Delete the old job and record the harness output as the new baseline.
Where the Speedup Is Genuinely Worth the Migration
Large project-reference graphs and monorepos
The payoff concentrates where the compiler is already the bottleneck: many packages, long reference chains, a CI job that spends minutes in tsc -b. These are the repos where typecheck / total runs above 0.5 and the Amdahl table promises a real 1.8–3x on the whole pipeline. They're also the repos whose monorepo tooling touches the compiler API most deeply, so the speedup and the migration risk scale together. Uncomfortable, but honest.
The local inner loop versus the CI wall clock
The asymmetry that matters: locally you run the type-checker dozens of times a day and it runs warm. In CI it runs once, cold, on fewer cores. The expected outcome for most teams is a much better inner loop and a modestly better pipeline. That's still worth having — developer time is expensive — but it's a different pitch than "our builds get 10x faster," and it should be sold internally that way.
Practical Checklist Before You Upgrade
| Check | Command | Pass condition |
|---|---|---|
| Compiler share of pipeline | phase-timer.mjs | typecheck/total ≥ 0.25 to be worth the effort |
| Cold vs warm gap | time-tsc.sh | Warm times show whether CI caching will help |
| Check-phase dominance | tsc --extendedDiagnostics | Check time / Total time is your realistic ceiling |
| Hot type-level code | --extendedDiagnostics → Instantiations | Under ~1M for a large app; millions means fix your types |
| API consumers | npm ls typescript + grep | Every hit has an owner and a validation plan |
| Effective config diff | tsc --showConfig on both | Diff reviewed and understood |
| Runner variance | hyperfine JSON p95 vs p50 | p95 < 2x p50, or fix the runners first |
The report's 11.9x may well be an accurate measurement of a real improvement. It is not a property of your codebase, and it won't predict your build times. Your number lives in timings.typecheck / total, and you can have it by lunchtime.
Further Reading
- A 10x Faster TypeScript — primary source for the native compiler port and its stated goals
- TypeScript performance wiki — the compiler team's own guidance on measuring and fixing slow builds
- TSConfig reference:
incrementaland project build options — semantics of.tsbuildinfoandtsc -b - hyperfine — benchmark runner used in the harness above
- typescript-eslint — the largest type-aware consumer of the compiler API in most repos
- Amdahl's law — the arithmetic behind the projection table
- The seed report — the 11.9x VS Code claim as it appeared in my feed (aggregator link)
More posts

Replacing tsup in a TS Library Monorepo: Vite+ 1.0 Build, DTS, and Publish in One Toolchain
How Vite+ 1.0's bundled build, DTS generation, and publish pipeline stacks up against tsup for TypeScript library monorepos, covering the migration path, CI integration, and where the new toolchain still falls short.

Reproducing Solar's 100× Solidity Compilation Benchmark, Stage by Stage
A stage-by-stage reproduction of Solar's claimed 100× Solidity compilation speedup, separating parsing, optimization, and code generation gains to show which smart-contract workloads actually benefit.

Why Appending to Your Agent's System Prompt Breaks Prompt Caching
Appending new instructions to an agent’s system prompt invalidates the cached prompt prefix, forcing full-price reprocessing and turning a $21 task into a $200 bill, so cache-stable prompt ordering is an architecture decision.
Loading comments…