Move a production TypeScript 6.0 codebase onto the TypeScript 7.0 beta (the Go-based tsgo compiler) without disrupting CI, editor tooling, or the existing type-check of record. The cutover keeps the old compiler installed as a fallback so you can revert in a single command.
Target audience: application and platform teams already on TypeScript 6.0 with strict enabled. Affected tooling: the local typecheck script, CI typecheck job, editor language server, and any build tool that shells out to tsc. Programmatic API consumers (ts-loader, ts-jest, ts-node) are out of scope - see the rollback section.
Prerequisites
- Node.js 20.10+ or 22+
- A project on TypeScript 6.0 that already compiles cleanly with
tsc --noEmit - No usage of
ignoreDeprecationsintsconfig.json - CI permissions to add a new job and modify the existing typecheck job
- A feature branch and a green main branch to compare against
If you are still on TypeScript 5.x, upgrade to 6.0 first and resolve any stableTypeOrdering diagnostics. The TS 7 beta only guarantees parity with code that compiles cleanly under TS 6.0 with stableTypeOrdering on and ignoreDeprecations off.
Step 1. Capture a baseline from the current compiler
Purpose: lock in the diagnostic set produced by TypeScript 6.0 so you can diff it against tsgo output.
git switch -c ts7-migration
npx tsc --noEmit --pretty false 2>&1 | tee baseline-tsc6.log
echo "exit=$?" >> baseline-tsc6.logExpected result:
- Exit code 0 written to the end of
baseline-tsc6.log - File committed-or-stashed so it survives the next steps
Recovery note: if the baseline is not clean on TS 6.0, stop here and fix the existing errors before installing tsgo.
Step 2. Install the TypeScript 7 beta alongside TS 6.0
Purpose: get the tsgo binary on the project without removing the existing tsc. The two coexist as separate devDependencies.
npm install -D @typescript/native-preview@betaThen add an explicit alias so the legacy typescript entry stays pinned to 6.0 and remains importable by tools that still need it:
{
"devDependencies": {
"@typescript/native-preview": "beta",
"typescript": "npm:@typescript/typescript6@^6.0.0"
}
}Reinstall after editing package.json:
rm -rf node_modules
npm installExpected result:
npx tsc --versionstill reports a 6.x versionnpx tsgo --versionreports a 7.0 beta version- No peer-dependency warnings about TypeScript versions
Recovery note: if a transitive dependency hard-pins typescript@^7, set the alias underoverridesinstead ofdevDependenciesso the resolution is enforced for the whole tree.
Step 3. Run tsgo against the existing tsconfig
Purpose: confirm structural parity with the TS 6.0 baseline before any tsconfig changes.
npx tsgo --noEmit --pretty false 2>&1 | tee baseline-tsgo.log
echo "exit=$?" >> baseline-tsgo.log
diff -u baseline-tsc6.log baseline-tsgo.log || trueExpected result:
- tsgo exits 0
- Diff against the TS 6.0 log is empty or limited to formatting and ordering of identical diagnostics
- Wall-clock time printed by
timeis materially lower than tsc on the same tree
If the diff contains new errors, the TS 7 beta type-checker is rejecting code that TS 6.0 accepted. Treat this as a real regression - file an issue at microsoft/typescript-go with a minimal repro and proceed only after triage.
Recovery note: if tsgo crashes (panic, segfault), capture the stderr and roll back via the rollback section. Do not paper over a crash by deleting node_modules/.cache.Step 4. Add a parallel npm script, do not replace the existing one
Purpose: expose tsgo as a sibling script so contributors can opt in locally while CI still gates on the old compiler.
{
"scripts": {
"typecheck": "tsc --noEmit",
"typecheck:next": "tsgo --noEmit"
}
}Expected result:
npm run typecheckstill uses TS 6.0 and is the authoritative checknpm run typecheck:nextruns tsgo and returns the same exit code on a clean tree
Recovery note: do not rename the existing script - downstream tooling and pre-commit hooks reference it by name.
Step 5. Wire tsgo into CI as a non-blocking canary
Purpose: collect parity data across real PRs before making tsgo the gate.
# .github/workflows/ci.yml
jobs:
typecheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: "22" }
- run: npm ci
- run: npm run typecheck
typecheck-next:
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: "22" }
- run: npm ci
- run: npm run typecheck:nextExpected result:
- Both jobs appear on every PR
typecheck-nextfailures do not block merges (continue-on-error: true)typecheck-nextwall-clock is visibly shorter thantypecheckon the same commit
Recovery note: if the canary job is noisy enough to confuse reviewers, disable the workflow rather than removing the dependency.
Step 6. Switch editors to the Native Preview language service
Purpose: surface tsgo diagnostics inside the editor so authors hit the new compiler before pushing.
- In VS Code, install the extension TypeScript Native Preview published by Microsoft.
- Disable or right-click-and-set-to-workspace-only the built-in TypeScript and JavaScript Language Features extension to avoid two language servers racing on the same files.
- Reload the window and confirm the status bar reports the native preview server.
Expected result:
- Hover, go-to-definition, and quick-fix work on a representative file
- Project-wide errors panel matches the CLI output from
tsgo --noEmit
Recovery note: the programmatic API in TS 7 beta is explicitly not stable. Tools such as ts-jest, ts-loader, tsx, and ts-node still need the TS 6.0 install you preserved under the typescript alias - do not uninstall it.Step 7. Bake parity, then promote tsgo to the gating job
Purpose: only flip the gate after sustained parity, not after a single green build.
- Wait for at least two weeks and 50 merged PRs of
typecheckandtypecheck-nextagreeing on every commit. - Record any commit where they disagreed and confirm it was triaged.
- Once stable, swap the scripts:
{
"scripts": {
"typecheck": "tsgo --noEmit",
"typecheck:legacy": "tsc --noEmit"
}
}Update the CI workflow so typecheck runs tsgo and the legacy job is the non-blocking canary. Leave the typescript alias in place for at least one more release cycle so programmatic-API consumers keep working.
Recovery note: keep the legacy job non-blocking but visible. If a regression slips through, you want one click to flip the gate back without a code change.
Verify
npx tsgo --noEmitexits 0 on a clean checkout of the migration branchnpx tsc --noEmitstill exits 0 with the same diagnostic count- CI shows both jobs green on three consecutive merges
- Editor go-to-definition resolves across a workspace import (cross-package, not just same-file)
- Watch a noisy directory (
npx tsgo --watch) and confirm rebuilds happen on save - note that incremental rechecking is prototype-quality in the beta and rebuilds may be full
Rollback
Rollback removes the TS 7 beta entirely and returns the project to a pure TS 6.0 toolchain.
- Revert the
package.jsonscripts sotypecheckrunstsc --noEmitagain. - Remove the beta and the alias:
npm uninstall @typescript/native-preview
npm install -D typescript@^6- Revert the CI workflow change that added the
typecheck-nextjob. - In editors, re-enable the built-in TypeScript and JavaScript Language Features extension and uninstall the Native Preview extension.
What rollback does NOT undo:
- Source edits made to satisfy tsgo diagnostics - those stay, and that is intentional
- New
baseline-tsgo.logandbaseline-tsc6.logartifacts in the repo - delete them manually - Cached language-service state in
.vscodeor per-developer settings - those are user-local
Irreversible: none of the steps in this guide are irreversible at the repository level. The only sticky change is editor extension state on individual machines.
What's next
Once tsgo is the gating compiler, audit the build tools that still depend on the TypeScript programmatic API and track their TS 7 support. When the TS 7 stable line ships and your programmatic-API consumers are compatible, drop the typescript@npm:@typescript/typescript6 alias and switch to the standard typescript package on the 7.x line. Add a CI step that prints tsgo --version so version drift between developers and CI is observable.
