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 ignoreDeprecations in tsconfig.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.log

Expected 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@beta

Then 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 install

Expected result:

  • npx tsc --version still reports a 6.x version
  • npx tsgo --version reports 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 under overrides instead of devDependencies so 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 || true

Expected 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 time is 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 typecheck still uses TS 6.0 and is the authoritative check
  • npm run typecheck:next runs 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:next

Expected result:

  • Both jobs appear on every PR
  • typecheck-next failures do not block merges (continue-on-error: true)
  • typecheck-next wall-clock is visibly shorter than typecheck on 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.

  1. In VS Code, install the extension TypeScript Native Preview published by Microsoft.
  2. 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.
  3. 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 typecheck and typecheck-next agreeing 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 --noEmit exits 0 on a clean checkout of the migration branch
  • npx tsc --noEmit still 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.

  1. Revert the package.json scripts so typecheck runs tsc --noEmit again.
  2. Remove the beta and the alias:
npm uninstall @typescript/native-preview
npm install -D typescript@^6
  1. Revert the CI workflow change that added the typecheck-next job.
  2. 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.log and baseline-tsc6.log artifacts in the repo - delete them manually
  • Cached language-service state in .vscode or 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.