Skip to content
Malik Hamza Shabbir
Toolingtypescripttsgobuild-toolsmigration

Migrating to TypeScript 7 (tsgo) Without Breaking Your Build: The Plugin, Transformer & Emit Gotchas

HSMalik Hamza ShabbirUpdated 8 min read

In short

For most real codebases the safe TypeScript 7 migration is not all-or-nothing. You type-check with tsgo for the speed and keep tsc for emit and anything that depends on the compiler API, because tsgo (the native Go port shipping with the 7.0 Beta announced 21 April 2026) has no support for tsconfig JS plugins, custom transformers, or a stable programmatic API until 7.1. If you need help untangling a build that broke on the jump, that is exactly the kind of work I do in app rescue and optimization.

Migrating to TypeScript 7 (tsgo) Without Breaking Your Build: The Plugin, Transformer & Emit Gotchas
On this page

tsgo, the native Go port of the TypeScript compiler shipping with the 7.0 Beta announced on 21 April 2026, is genuinely fast, but for most real codebases you cannot just swap it in for tsc. The safe migration is a dual-compiler setup: you type-check with tsgo to get the speed, and you keep the JavaScript tsc for emit and for anything that touches the compiler API, custom transformers, or tsconfig plugins. tsgo does not support those yet, and the stable programmatic API is deferred to 7.1. This article is the tsconfig and CI layout I use to get the win without breaking the build, plus a checklist of which tools go quiet when you flip the switch.

What actually changes in TypeScript 7 (tsgo)?

TypeScript 7 is a rewrite of the compiler in Go, distributed as a separate binary called tsgo, and the headline is type-checking speed, not new language features. The type system and tsconfig semantics are meant to match the existing compiler, so your code does not need to change. What changes is the engine doing the checking.

The thing the "10x faster" headline buries is what the Go port does not carry over yet. The 7.0 Beta is explicit that the native compiler is still missing pieces that a lot of toolchains quietly depend on. So the right mental model is not "TypeScript got faster, upgrade everything." It is "there is a fast new checker that does most of what tsc does, and a list of things it does not do yet." Your migration plan lives entirely in that gap.

Here is the split I work from:









CapabilityJavaScript tsc (6.x / 7.x)Native tsgo (7.0 Beta)
Type-checking (--noEmit)YesYes, and much faster
JS emit (.js, .d.ts, source maps)YesPartial / not the recommended path yet
tsconfig plugins (language service plugins)YesNo
Custom transformers (ts-patch, ttypescript style)YesNo
Stable programmatic compiler APIYesDeferred to 7.1
--build / project referencesYesIn progress, verify per release
Editor language serviceYesNew LSP-based server, separate track

The two rows that decide your whole strategy are plugins/transformers and the compiler API. If your build does not touch either, you are close to a drop-in. If it does, you keep tsc in the loop on purpose.

Why can't I just use tsgo for everything?

Because emit, plugins, transformers, and the compiler API are exactly the surfaces tsgo has not finished, and a surprising amount of tooling is built on top of them. The failures are not loud crashes. They are silent: a transformer that used to inject code now does nothing, and your runtime breaks far away from the build step.

The pattern I keep seeing is this. A team runs tsgo over the repo, sees zero type errors in a fraction of the old time, and assumes the migration is done. Then a transformer that was rewriting decorators, stripping a dev-only branch, or generating an injection token simply stops running, because tsgo never loaded it. There is no error. The output just lacks the code the transformer used to add. You find out in production or in a test that exercises the transformed path.

This is why I treat tsgo as a checker first and an emitter much later. Type-checking is the part that is both finished and where almost all the speed lives. Emit and the plugin pipeline are where the gaps are. Splitting those two jobs across two compilers is not a hack, it is the supported posture for the Beta period.

How do I set up a dual-compiler tsconfig?

Use one base config for shared options, a tsconfig.typecheck.json that tsgo runs with --noEmit, and a tsconfig.build.json that the JavaScript tsc uses for emit and transformers. tsgo gets the fast path, tsc keeps the build correct.

Start with the base:

JSONC
// tsconfig.base.json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "strict": true,
    "skipLibCheck": true,
    "esModuleInterop": true
  }
}

The type-check config that tsgo runs. Note it carries no plugins and never emits:

JSONC
// tsconfig.typecheck.json  (run by tsgo)
{
  "extends": "./tsconfig.base.json",
  "compilerOptions": {
    "noEmit": true,
    "incremental": false
  },
  "include": ["src/**/*.ts", "src/**/*.tsx"]
}

The build config that the JavaScript tsc runs, where the transformers and plugins still live:

JSONC
// tsconfig.build.json  (run by tsc, possibly via ts-patch)
{
  "extends": "./tsconfig.base.json",
  "compilerOptions": {
    "noEmit": false,
    "declaration": true,
    "outDir": "dist",
    "plugins": [
      { "transform": "./scripts/my-transformer.ts" }
    ]
  },
  "include": ["src/**/*.ts", "src/**/*.tsx"]
}

Then your package.json scripts make the division explicit:

JSONC
{
  "scripts": {
    "typecheck": "tsgo --project tsconfig.typecheck.json",
    "typecheck:legacy": "tsc --noEmit --project tsconfig.typecheck.json",
    "build": "tsc --project tsconfig.build.json"
  }
}

The point of keeping typecheck:legacy around is a safety valve. If tsgo and tsc ever disagree about your code, you want to be able to run both and diff the diagnostics. During the Beta I run that comparison once per upgrade rather than trusting tsgo blind.

How do I wire this into CI without flakiness?

Run tsgo as a fast, blocking type-check gate, and run the JavaScript tsc build as a separate job that produces the actual artifacts. Pin both compiler versions exactly, because a Beta moves quickly and you do not want a floating tag changing your checker mid-sprint.

A minimal GitHub Actions shape:

YAML
jobs:
  typecheck:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 22 }
      - run: npm ci
      # tsgo: fast gate, fails the PR on any type error
      - run: npm run typecheck

  build:
    runs-on: ubuntu-latest
    needs: typecheck
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 22 }
      - run: npm ci
      # tsc: real emit, runs transformers/plugins, produces dist/
      - run: npm run build

Two rules I hold to during the Beta window. First, pin exact versions in package.json (no ^) for both @typescript/native-preview (or whatever the published tsgo package name is in your release) and typescript. A "fast checker that suddenly reports new errors" is a miserable thing to debug on a Friday. Second, make the tsgo job blocking but keep an escape hatch: if tsgo throws an internal error on a file (it can, it is Beta), let me fall back to typecheck:legacy for that run rather than blocking every merge on a compiler bug.

If you maintain a monorepo with project references, verify --build behavior on tsgo per release before you rely on it. That feature was still being completed during the Beta, so I keep reference-graph builds on tsc until I have personally watched tsgo produce identical output.

Which tools silently break when I switch to tsgo?

The ones that hook into emit, transformers, or the compiler API: ts-patch, transformer-based codegen, some bundler TS plugins, and any custom script that imports the typescript package programmatically. They do not error, they just stop doing their job, which is why this list is worth checking line by line.

Here is the checklist I run through before declaring a project tsgo-ready:

  • ts-patch / ttypescript-style transformers: do not run under tsgo. Keep them on tsc in the build job. This includes anything in your tsconfig plugins array with a transform field.

  • NestJS / Angular-style decorator metadata emit: depends on emit and sometimes on transformers. Verify the emitted output, do not assume.

  • typia, tRPC codegen, zod-from-type generators, transformer-driven DI: these are transformer tools. They are silent no-ops under tsgo. Confirm they run in the tsc build.

  • ESLint type-aware rules (@typescript-eslint with parserOptions.project): these call the JavaScript TypeScript API. They keep working because they use tsc's API, not tsgo. Do not point them at tsgo expecting a speedup yet.

  • Bundler TS integrations (some Vite, esbuild, Rollup plugins): most bundlers strip types with their own transpiler and only call TS for checking, so they are usually fine, but any plugin that asks TypeScript to emit needs verification.

  • Custom scripts importing typescript directly: anything doing import ts from "typescript" to build a Program, walk the AST, or run diagnostics relies on the API that is deferred to 7.1. These stay on the JavaScript package.

  • API Extractor, TypeDoc, ts-morph: all consume the compiler API. They stay on tsc until the 7.1 API lands and they update.


The honest summary is that type checking moves to tsgo cleanly, and almost everything that reads or rewrites your program stays on tsc. That is fine. The dual setup is designed to let those two worlds coexist.

What should my migration order be?

Adopt tsgo as a non-blocking type-check first, compare its diagnostics against tsc, then promote it to a blocking gate, and only consider tsgo emit once the 7.1 compiler API ships and your tools update. Never start by moving emit.

The order that has worked for me:

  1. Add tsgo as typecheck alongside the existing typecheck:legacy. Run both, diff the output. Resolve any genuine disagreements (usually they reveal real but previously tolerated issues).

  2. Make the tsgo typecheck job blocking in CI once it agrees with tsc across a few PRs.

  3. Keep all emit, transformers, and plugins on tsc in a separate build job. Do not touch this until 7.1.

  4. Inventory every transformer and API consumer using the checklist above. Document which job owns each one.

  5. Revisit emit and the compiler API after 7.1 lands and your transformer tools publish tsgo-compatible versions. Migrate emit per package, not all at once.


If you are landing here because a build already broke on the jump and a transformer silently dropped out, that untangling is the core of what I do in app rescue and optimization . The fix is rarely exotic. It is usually drawing the line between "check" and "emit" cleanly and putting the right compiler on each side.

I wrote up a related upgrade landmine in fixing React Hook Form after React Compiler 1.0 , which bites the same way.

A last note on expectations. The speed is real and the type-check gate genuinely gets faster, which matters most on large codebases where tsc --noEmit was the slow part of CI. But the Beta is a Beta. Pin your versions, keep tsc in the loop for everything it still owns, and do not let the headline talk you into moving emit before the tooling underneath you has caught up. If you want a second set of eyes on a migration plan or a build that went quiet, my contact page is the place to reach me.

FAQ

Can I fully replace tsc with tsgo in TypeScript 7?

Not yet for most projects, because tsgo in the 7.0 Beta has no support for tsconfig JS plugins, custom transformers, or a stable compiler API, so anything depending on those still needs the JavaScript tsc.

Does tsgo support custom transformers like ts-patch or ttypescript?

No, tsgo does not run custom transformers or `plugins` entries in tsconfig today, so transformer-based tools such as ts-patch keep needing the original tsc binary.

Will my IDE language service tools and ESLint type-aware rules keep working?

They keep working as long as they call the JavaScript TypeScript API, since tsgo has not exposed a stable programmatic compiler API and that is deferred to 7.1.

What is the safest way to adopt tsgo right now?

Run tsgo as your fast type-check gate in CI and locally while keeping tsc as the emit and API path, which gives you most of the speed without breaking codegen or plugin-driven builds.

When does TypeScript 7 plan a stable compiler API for tools?

Per the 7.0 Beta announcement on 21 April 2026, stable is planned within roughly two months and the compiler API for tooling is deferred to 7.1.

Working on something like this?

I build web apps, AI features, and mobile products for clients. If this article matches a problem you have, tell me about it.

Start a conversation
HS

Malik Hamza Shabbir · Full-Stack & AI Engineer

I build full-stack and AI products solo: a reputation SaaS in production, RAG pipelines, and React Native apps. I write from what I ship, not from documentation summaries.

Related articles