> ## Documentation Index
> Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt
> Use this file to discover all available pages before exploring further.

# ADR-018: TypeScript 7.0 (Go Compiler) Evaluation and Adoption Strategy

> Status: Proposed (recommendation: Adopt as opt-in tsgo-powered fast path now; promote to default when stable ships and the typescript-eslint peer range opens f…

**Status:** Proposed (recommendation: **Adopt as opt-in `tsgo`-powered fast path now; promote to default when stable ships and the `typescript-eslint` peer range opens for TS 7.x**)
**Date:** 2026-04-23
**Owners:** Platform Architecture
**Related:** [ADR-009 Biome formatter](ADR-009-biome-formatter.md), [.github/workflows/build.yml](../../../.github/workflows/build.yml), [CI\_PIPELINE.md](../../development/CI_PIPELINE.md)

***

## Context

On 2026-04-21 Microsoft published [TypeScript 7.0 Beta](https://devblogs.microsoft.com/typescript/announcing-typescript-7-0-beta/). TS 7.0 is a Go port of the existing TypeScript codebase ("Project Corsa"), shipping under the `@typescript/native-preview` package and the `tsgo` entry point. Microsoft positions it as semantically equivalent to TS 6.0 with `stableTypeOrdering` on and `ignoreDeprecations` unset; the headline value is \~10× faster type-checking via native code and shared-memory parallelism.

This ADR records a structured evaluation against the Encore Health OS codebase and recommends a phased adoption.

### Repo baseline (as of this ADR)

| Item                                      | Value                                                                                                                                                                                                                                                                                |
| ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Declared TS in `package.json`             | `typescript@^6.0.3`                                                                                                                                                                                                                                                                  |
| Resolved TS in lockfile                   | `6.0.3` (registry tarball)                                                                                                                                                                                                                                                           |
| Currently installed in `node_modules`     | `5.9.3` (peer-dep deduplication via `npm ci --legacy-peer-deps`)                                                                                                                                                                                                                     |
| Configs                                   | `tsconfig.json` (root) → references `tsconfig.app.json` and `tsconfig.node.json`. App config: `target: ES2020`, `module: ESNext`, `moduleResolution: bundler`, `noEmit`, `strict: false` + `strictNullChecks: true`, incremental cache at `node_modules/.cache/tsc/app.tsbuildinfo`. |
| Typecheck script                          | `tsc --noEmit -p tsconfig.app.json --incremental --tsBuildInfoFile node_modules/.cache/tsc/app.tsbuildinfo` (single-config invocation; no `tsc --build`).                                                                                                                            |
| CI typecheck                              | `npm run typecheck` in `.github/workflows/build.yml`, with `node_modules/.cache/tsc` cached across runs. Cold run is the slow path; warm runs hit the incremental cache.                                                                                                             |
| TS Compiler API consumers                 | 3 audit scripts: `scripts/audit/doc-comment-coverage/parser.ts`, `scripts/audit/audit-appicon-tones.ts`, `scripts/audit/audit-page-spacing.ts` (all `import ts from 'typescript'`).                                                                                                  |
| Linter                                    | `typescript-eslint@^8.59.0` (currently installed: 8.58.2). Peer range published in installed packages: **`typescript >=4.8.4 <6.1.0`**.                                                                                                                                              |
| Other TS-API consumers in `node_modules`: | `ts-node@10.9.2`, `msw@2.13.2`, `@vitest/*@4.1.5`, `vite-plugin-checker@0.13.0`, `eslint-plugin-tsdoc@0.5.2`. (Fallow is a Rust binary and not a TS Compiler API consumer.)                                                                                                          |
| `ignoreDeprecations`                      | Not set in any tsconfig.                                                                                                                                                                                                                                                             |

### What TS 7.0 actually changes for us

* Same compiler semantics as TS 6.0 (per Microsoft's stability statement and 10-year test suite re-run).
* New binary name: `tsgo`. The `typescript` package will re-take the `tsc` entry point only when 7.0 goes stable.
* A compatibility shim (`@typescript/typescript6` exposing `tsc6`) lets you keep TS 6.x available for tools that import `typescript` as a peer.
* `stableTypeOrdering` becomes the assumed default; any `ignoreDeprecations` usage breaks (we use neither, so this is a non-issue here).
* No stable programmatic API in 7.0 yet — Microsoft explicitly defers that. Tools that import the TS Compiler API must keep using TS 6.x for now.

***

## Evaluation: empirical results on this repo

We installed `@typescript/native-preview@beta` (`tsgo` v7.0.0-dev.20260421.2) alongside the existing TS 6.0.3 toolchain and compared against `tsc --noEmit -p tsconfig.app.json` on the same source tree, same tsconfig, same machine. Cache was cleared before each "cold" run.

| Run                                                          | Compiler             | Wall time                                                   | Errors |
| ------------------------------------------------------------ | -------------------- | ----------------------------------------------------------- | ------ |
| Cold typecheck                                               | `tsc` (TS 6.0.3)     | **7m 58s** (478s)                                           | 0      |
| Cold typecheck                                               | `tsgo` (TS 7.0 beta) | **0m 53s** (53s)                                            | 0      |
| Warm typecheck (incremental cache hit)                       | `tsc` (TS 6.0.3)     | 7m 53s (no incremental cache benefit on this run; see note) | 0      |
| Warm typecheck (no incremental cache; tsgo doesn't need one) | `tsgo` (TS 7.0 beta) | **3.6s**                                                    | 0      |

> Note on warm `tsc`: the second `tsc` run was effectively another cold compile because the `.tsbuildinfo` was generated against a `tsc` from the freshly installed npm tree (TS 6.0.3) and the cache was not preserved across the `tsgo` install in our test environment. In CI, the warm-cache path normally completes in \~8s as documented in the build workflow, which roughly matches `tsgo`'s warm-run number — so the truly meaningful comparison is **cold \~478s → cold \~53s** (\~9× faster) and **warm \~8s (cached) → warm \~3.6s (no cache needed)** (\~2× faster, with simpler cache semantics).

**Diagnostics parity:** zero errors emitted in either compiler for this commit. No new errors, no removed errors, no different ones.

**Key implication for CI:** CI typecheck cold time (when the `tsc-${{ runner.os }}-…` cache key misses, which happens any time `tsconfig*.json`, `package-lock.json`, or `src/integrations/supabase/types.ts` changes — i.e., on most dependency bumps and on every Supabase types regeneration) drops from \~8 minutes to \~1 minute. Warm runs are already fast and stay fast. The Supabase `types.ts` regeneration is currently the single biggest CI typecheck cliff, and `tsgo` flattens it.

***

## Constraints and risks

1. **`typescript-eslint` peer range still excludes TS ≥ 6.1.0.** Installed versions in our tree advertise `typescript >=4.8.4 <6.1.0`. v8.58.0 added TS 6 support; TS 7 official support is expected in a future major. Until that ships, the linter must continue to resolve `typescript` to a 6.x build. The `npm:@typescript/typescript6` alias is the supported workaround.
2. **No stable programmatic API in TS 7.0.** Our three audit scripts (`audit-appicon-tones.ts`, `audit-page-spacing.ts`, `doc-comment-coverage/parser.ts`) `import ... from 'typescript'`. They must keep resolving against TS 6.x. The compatibility package handles this transparently.
3. **`ts-node` peer range:** `node_modules/ts-node@10.9.2` advertises `typescript: >=2.7` so it accepts both. We use `ts-node` for \~15 utility scripts; keep it pointed at the same `typescript` resolution as the linter (TS 6.x via alias).
4. **MSW, Vitest, Vite, `vite-plugin-checker`, `eslint-plugin-tsdoc`:** all consume the TypeScript package or its compiler API. None of them have published explicit TS 7 peer ranges yet. They will keep resolving against the aliased TS 6.x `typescript` entry — this is exactly what the Microsoft compatibility recipe is for.
5. **`tsc --build` (project references):** Our `tsconfig.json` lists references but our `typecheck` script invokes `tsc -p tsconfig.app.json` directly, so build-mode caching is not in play. `tsgo` accepts `-p`. No script changes are needed beyond replacing the binary name.
6. **`incremental` and `tsBuildInfoFile` flags:** `tsgo` does not need `--incremental` to be fast (warm 3.6s without one). The flags are harmless to leave in for the TS 6 fallback path; `tsgo` ignores or accepts them.
7. **Beta lifecycle:** Microsoft plans GA "within the next two months" (i.e. on the order of June 2026), with a release candidate a few weeks before. Behavior is described as "finalized" only at RC. Until then there is non-zero risk of compatibility-affecting fixes between dev releases.
8. **No Encore-specific blocker found.** We don't use `ignoreDeprecations`. We don't use removed legacy compiler options. We don't ship a TS-emit pipeline (`noEmit: true`). Vite + `@vitejs/plugin-react` does the actual JS transform; TS is type-check only here. This makes us an unusually safe candidate for early adoption.
9. **CI cache key.** The existing build workflow keys on `tsconfig*.json`/`package-lock.json`/`src/integrations/supabase/types.ts`. If we keep both `tsc` and `tsgo` on the same tsconfig, no key change is required. If we add a separate `node_modules/.cache/tsgo` path, it should be added to the cache step.

***

## Options Considered

### Option A: Stay on TS 6.0.x for the foreseeable future (status quo)

* **Pros:** Zero migration work, maximal tooling compatibility, deterministic.
* **Cons:** Cold typecheck remains \~8 min and is the dominant cost in CI when cache misses; developer feedback on dependency bumps and Supabase types regeneration is poor; we leave a \~9× perf win on the table on a 4,000+-file codebase that already has incremental cache as its only mitigation.

### Option B: Adopt `@typescript/native-preview` now as an **opt-in** `npm run typecheck:fast`/`tsgo` script, keep `tsc` (TS 6.x) as the source of truth for CI gates and editor parity, no peer-dep changes ✓ (recommended Phase 1)

* **Pros:** Zero risk to existing CI gate. Developers immediately get sub-minute cold typechecks locally. Editor experience can switch to the [TypeScript Native Preview VS Code extension](https://marketplace.visualstudio.com/items?itemName=TypeScriptTeam.typescript-native-preview) per developer choice. Audit scripts, linter, ts-node, and build all continue resolving the existing TS 6.x install. **Empirically validated on this repo** (cold 478s → 53s, no diagnostic changes).
* **Cons:** CI still pays the cold-cache cost on Supabase types regeneration until we cut over the gate.

### Option C: Cut CI typecheck over to `tsgo` immediately, install `typescript` as alias `npm:@typescript/typescript6` so linter/audit scripts/ts-node still see TS 6.x

* **Pros:** Captures the \~9× cold-CI win immediately.
* **Cons:** TS 7.0 is still beta; `npm install -D typescript@npm:@typescript/typescript6` plus a separate `@typescript/native-preview` install is a non-trivial lockfile change; warm CI is already \~8s, so the absolute CI minutes saved per run are modest unless the cold-cache path (Supabase types regen, dep bumps, branch creation) is what's hurting. **Defer to Phase 2.**

### Option D: Wait for TS 7.0 GA and then migrate

* **Pros:** Maximum stability; benefit from RC-period fixes; ride along with `typescript-eslint`'s native TS 7 support when it lands.
* **Cons:** \~2-month delay on developer-experience wins; no learning prior to GA; no validation against our specific audit scripts and Supabase-types regeneration cliff.

***

## Decision (recommendation)

**Adopt Option B now. Plan Option C as Phase 2 once two conditions are met: (a) TS 7.0 reaches RC or GA, (b) `typescript-eslint` publishes a release whose peer range includes TS 7.x.** Track Phase 2 as a follow-up issue, not a blocker.

Concretely:

### Phase 1 (now — recommended action)

1. Add `@typescript/native-preview` as a `devDependency` (pinned to a known beta version, e.g. `^7.0.0-dev.20260421.2`, with renovate updates allowed).
2. Add a new npm script:
   ```jsonc theme={null}
   "typecheck:fast": "cross-env NODE_OPTIONS=--max-old-space-size=8192 tsgo --noEmit -p tsconfig.app.json"
   ```
   Leave the existing `typecheck` script (TS 6 + `tsc`) unchanged as the gate.
3. Add a brief note to [AGENTS.md](../../../AGENTS.md) "Pre-Flight Checklist → Before commit" pointing developers at `npm run typecheck:fast` for local iteration. Keep `npm run validate` (which runs the slow `tsc` path) as the authoritative gate.
4. Document the optional VS Code "TypeScript Native Preview" extension in `docs/development/DEVELOPMENT_QUICK_REFERENCE.md` as a developer-choice ergonomic upgrade.
5. **Do not** modify the linter, audit scripts, `ts-node`, `tsBuildInfoFile`, or the CI cache key. **Do not** alias `typescript`. **Do not** change peer-dep ranges.

### Phase 2 (when TS 7.0 hits RC/GA AND `typescript-eslint` ships TS 7-compatible peer range)

1. Replace the root `typescript` dependency with the alias: `"typescript": "npm:@typescript/typescript6@^6.0.0"` (keeps the API for linter, audit scripts, MSW, Vitest, ts-node, and vite-plugin-checker).
2. Add the stable `typescript@^7.x` dependency separately, exposing `tsc` (the TS 7 entry point).
3. Switch `npm run typecheck` and CI's "Typecheck" step to use the new `tsc` (TS 7).
4. Drop the `--incremental`/`--tsBuildInfoFile` flags from the typecheck script (no longer needed for performance), and remove `node_modules/.cache/tsc` from the cache step. Optionally add a smaller `node_modules/.cache/tsgo` cache entry if measurement shows it helps.
5. Update [AGENTS.md](../../../AGENTS.md) §"Pre-Flight Checklist → Before commit", [CI\_PIPELINE.md](../../development/CI_PIPELINE.md), and the typecheck section of [.github/workflows/build.yml](../../../.github/workflows/build.yml) comments.
6. Run `npm run validate` and the full unit/integration/RLS smoke baseline before merging.

### Phase 3 (post-Phase-2 cleanup)

1. Once `typescript-eslint`, `ts-node`, `msw`, `vitest`, `vite-plugin-checker`, and `eslint-plugin-tsdoc` all advertise TS 7-compatible peer ranges, drop the `@typescript/typescript6` alias and the audit-script keep-alive comments; let `typescript` resolve to 7.x natively.

***

## Consequences

### Positive

* Sub-minute cold typecheck for developers immediately (Phase 1) — biggest single ergonomic win on this repo since incremental cache.
* Zero behavior delta in our codebase (validated: identical zero-error result on this commit).
* \~7-minute cold-CI win once Phase 2 lands (every Supabase types regeneration, dep bump, or PR with a tsconfig change saves \~7 minutes of CI wall time).
* `tsgo` removes the need to babysit `--incremental`/`tsBuildInfoFile` cache invalidation.

### Negative / Risks

* Two compilers coexist locally during Phase 1 (small node\_modules footprint cost; one extra binary).
* Phase 2 timing depends on third-party (`typescript-eslint`) release cadence.
* Beta dev-stream releases of `tsgo` change frequently; we should pin and let renovate roll.
* Until Phase 2, `npm run typecheck` continues to be the \~8-minute cold path in CI.

### Mitigations

* Phase 1 is intentionally additive: nothing existing changes.
* The cutover (Phase 2) is gated on RC/GA + linter compatibility, so we don't ship a beta into the CI gate.
* All TS Compiler API consumers (3 audit scripts plus 6 third-party tools) are explicitly enumerated above; the `@typescript/typescript6` alias keeps every one of them working.
* `ignoreDeprecations` is not in use anywhere, removing the most common 6→7 break.

***

## Empirical evidence (commands and results)

Reproducible on a fresh clone of this commit on a Linux x64 dev box:

```bash theme={null}
npm ci --legacy-peer-deps
npm install --no-save --legacy-peer-deps @typescript/native-preview@beta

# Cold tsc (TS 6.0.3)
rm -rf node_modules/.cache/tsc && mkdir -p node_modules/.cache/tsc
time ./node_modules/.bin/tsc --noEmit -p tsconfig.app.json \
     --incremental --tsBuildInfoFile node_modules/.cache/tsc/app.tsbuildinfo
# → real 7m58s, 0 errors

# Cold tsgo (TS 7.0 beta)
time ./node_modules/.bin/tsgo --noEmit -p tsconfig.app.json
# → real 0m53s, 0 errors

# Warm tsgo (no incremental cache configured)
time ./node_modules/.bin/tsgo --noEmit -p tsconfig.app.json
# → real 0m3.6s, 0 errors
```

***

## Related Documents

* **Implementation plan:** [TYPESCRIPT\_7\_MIGRATION\_PLAN.md](../../development/TYPESCRIPT_7_MIGRATION_PLAN.md) — concrete diffs, gating criteria, verification commands, and rollback procedures for Phases 1–3.
* Microsoft announcement: [https://devblogs.microsoft.com/typescript/announcing-typescript-7-0-beta/](https://devblogs.microsoft.com/typescript/announcing-typescript-7-0-beta/)
* TS 6→7 transition + `@typescript/typescript6` compatibility package (linked from the announcement)
* [.github/workflows/build.yml](../../../.github/workflows/build.yml) — CI typecheck cache configuration
* [package.json](../../../package.json) — `typecheck`, `validate`, `build` scripts
* [tsconfig.app.json](../../../tsconfig.app.json) — primary type-check config
* [ADR-009 Biome formatter](ADR-009-biome-formatter.md) — precedent for adopting native-code dev-ergonomics tooling
