Skip to content

chore(build): make typecheck cacheable and incremental - #372

Merged
omridevk merged 1 commit into
mainfrom
chore/incremental-typecheck
Aug 9, 2026
Merged

chore(build): make typecheck cacheable and incremental#372
omridevk merged 1 commit into
mainfrom
chore/incremental-typecheck

Conversation

@omridevk

@omridevk omridevk commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Before

turbo.json's typecheck task declared no outputs:

"typecheck": {"dependsOn": ["^build"]}

Every package's typecheck script is tsc -p tsconfig.json --noEmit, which produces no artifact.
With no output to hash/restore, tsc had no incremental state either, so every cache miss was a full
cold typecheck — across all 50 packages/apps with a typecheck script (the dispatch estimated 40 from
a shallower glob; the real count, including packages/extensions/* and e2e/e2e-utils, is 50).

After

  • Every package/app tsconfig that a typecheck script actually runs gets "incremental": true and
    "tsBuildInfoFile": ".tsbuildinfo" in compilerOptions. This must be per-package rather than in
    tsconfig.base.json: tsBuildInfoFile resolves relative to the config file that declares it
    (TS docs), so putting it in the shared
    base would make all packages collide on one root .tsbuildinfo.
  • turbo.json's typecheck task now declares "outputs": [".tsbuildinfo", "**/.tsbuildinfo"] (the
    glob also covers nested tsconfigs, e.g. @conciv/extension-tanstack's test/host/tsconfig.json and
    test/host/conciv/tsconfig.json, and the example app's conciv/extensions/tsconfig.json).
  • .gitignore's existing *.tsbuildinfo (line 4) already covers the per-package .tsbuildinfo path —
    confirmed with git check-ignore, no duplicate entry added.

A bug this surfaced and fixed along the way

18 packages also have a tsconfig.build.json (declaration-emit config used by the build script, e.g.
tsc -p tsconfig.build.json) that extends: "./tsconfig.json". Since build has no dependency on that
same package's own typecheck task, turbo can run both concurrently — and because tsconfig.build.json
inherits tsBuildInfoFile from the tsconfig.json I just edited, both tsc invocations would write to
the same .tsbuildinfo file at once. This reproduced as real breakage: a forced full run intermittently
dropped .d.ts output for @conciv/ui-kit-system, @conciv/protocol, @conciv/solid-streamdown, etc.,
which cascaded into downstream build failures. Fixed by giving each of those 18 tsconfig.build.json
files its own distinct "tsBuildInfoFile": ".build.tsbuildinfo" (still covered by the same gitignore
glob, verified separately).

Verification (foreground, full machine under load ~260-300 all day)

1. Cold run — green.

pnpm turbo run typecheck --force
 Tasks:    92 successful, 92 total
Cached:    0 cached, 92 total
  Time:    9m46.09s

2. Warm run — full cache hit.

pnpm turbo run typecheck
 Tasks:    92 successful, 92 total
Cached:    92 cached, 92 total
  Time:    1.554s >>> FULL TURBO

3. The one that matters — a dependency change still invalidates dependents, and doesn't get a false
cache hit.
Planted a real type error in @conciv/ui-kit-system (LIST_PANEL_MESSAGE changed from a
string export to a number), which is consumed as class={LIST_PANEL_MESSAGE} in
@conciv/ui-kit-tap/src/suggestion-listbox.tsx:

pnpm turbo run typecheck --filter=@conciv/ui-kit-tap
@conciv/ui-kit-tap:typecheck: cache miss, executing 347f5a05781cbda5
@conciv/ui-kit-tap:typecheck: $ tsc -p tsconfig.json --noEmit
@conciv/ui-kit-tap:typecheck: src/suggestion-listbox.tsx(109,40): error TS2322: Type 'number' is not assignable to type 'string'.
Failed:    @conciv/ui-kit-tap#typecheck

Cache miss (not a stale hit) and a genuine failure at the exact usage site. Reverted the planted error
afterward and confirmed a clean tree (git status shows only the intended 72-file diff — 53
tsconfig.json + 18 tsconfig.build.json + turbo.json) and that the re-run goes back to a legitimate
cached pass.

Also confirmed: 71 .tsbuildinfo files were produced across the tree after the cold run, and
git status is clean of them (all covered by the existing *.tsbuildinfo gitignore pattern).

Gates

  • pnpm lint — 97/97 tasks, 0 errors (pre-existing warnings in an unrelated React example app only)
  • pnpm format:check — all files correctly formatted
  • pnpm exec fallow audit --changed-since main --format json — verdict pass, 0 introduced findings
    (dead_code_introduced: 0, complexity_introduced: 0, duplication_introduced: 0)

No changeset: this is build config only, no published package behavior changes.

🤖 Generated with Claude Code

…oFile

tsc -p tsconfig.json --noEmit produced no artifact, so turbo's typecheck
task (no outputs declared) was always a cold, non-incremental full check
on every cache miss across all 50 packages with a typecheck script.

Add per-package incremental:true + tsBuildInfoFile:".tsbuildinfo" to every
package/app tsconfig a typecheck script actually runs (tsBuildInfoFile
resolves relative to the declaring config, so this must be per-package,
not in tsconfig.base.json, or all packages would collide on one file).
Declare outputs:[".tsbuildinfo", "**/.tsbuildinfo"] on turbo.json's
typecheck task so the buildinfo is cached and content-hashed alongside
the task.

Packages that also have a tsconfig.build.json (declaration-emit config
used by the build script) get their own distinct tsBuildInfoFile
(.build.tsbuildinfo) there: it extends the same tsconfig.json, so it
would otherwise silently inherit the same buildinfo path as the
typecheck config and race with it when turbo runs a package's build and
typecheck tasks concurrently (build has no dependency on that package's
own typecheck), corrupting the shared file and dropping declaration
output under load.

Verified: cold `turbo run typecheck --force` green across all 92 tasks;
an immediate re-run is FULL TURBO (92/92 cached); planting a type error
in @conciv/ui-kit-system correctly invalidates and fails
@conciv/ui-kit-tap's typecheck (cache miss, not a stale hit) once
reverted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@omridevk, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 5 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 300ddb07-acf3-4d44-b046-a777c5d3a936

📥 Commits

Reviewing files that changed from the base of the PR and between 1ab496e and eb7de85.

📒 Files selected for processing (72)
  • apps/conciv/tsconfig.json
  • apps/examples/tanstack-start/conciv/extensions/tsconfig.json
  • apps/examples/tanstack-start/tsconfig.json
  • apps/site/tsconfig.json
  • apps/storybook/tsconfig.json
  • e2e/e2e-utils/tsconfig.json
  • packages/bundle-size/tsconfig.json
  • packages/cli/tsconfig.json
  • packages/client/tsconfig.json
  • packages/contract/tsconfig.json
  • packages/core/tsconfig.json
  • packages/db/tsconfig.json
  • packages/embed/tsconfig.build.json
  • packages/embed/tsconfig.json
  • packages/extension-compiler/tsconfig.json
  • packages/extension-testkit/tsconfig.json
  • packages/extension/tsconfig.json
  • packages/extensions/ios/tsconfig.build.json
  • packages/extensions/ios/tsconfig.json
  • packages/extensions/page/tsconfig.build.json
  • packages/extensions/page/tsconfig.json
  • packages/extensions/recorder/tsconfig.build.json
  • packages/extensions/recorder/tsconfig.json
  • packages/extensions/tanstack/test/host/conciv/tsconfig.json
  • packages/extensions/tanstack/test/host/tsconfig.json
  • packages/extensions/tanstack/tsconfig.build.json
  • packages/extensions/tanstack/tsconfig.json
  • packages/extensions/terminal/tsconfig.build.json
  • packages/extensions/terminal/tsconfig.json
  • packages/extensions/test-runner/tsconfig.build.json
  • packages/extensions/test-runner/tsconfig.json
  • packages/extensions/try-it/tsconfig.build.json
  • packages/extensions/try-it/tsconfig.json
  • packages/extensions/whiteboard/tsconfig.build.json
  • packages/extensions/whiteboard/tsconfig.json
  • packages/grab/tsconfig.json
  • packages/harness-init/tsconfig.json
  • packages/harness-testkit/tsconfig.json
  • packages/harness/tsconfig.json
  • packages/it/tsconfig.json
  • packages/mascot/tsconfig.json
  • packages/oxlint-plugin/tsconfig.json
  • packages/page/tsconfig.json
  • packages/plugin/tsconfig.json
  • packages/preact/tsconfig.json
  • packages/protocol/tsconfig.build.json
  • packages/protocol/tsconfig.json
  • packages/publish/tsconfig.json
  • packages/react/tsconfig.json
  • packages/serve/tsconfig.json
  • packages/solid-diffs/tsconfig.build.json
  • packages/solid-diffs/tsconfig.json
  • packages/solid-streamdown/tsconfig.build.json
  • packages/solid-streamdown/tsconfig.json
  • packages/solid/tsconfig.json
  • packages/storage-history/tsconfig.json
  • packages/tools/tsconfig.json
  • packages/try/tsconfig.json
  • packages/ui-kit-chat-tools/tsconfig.build.json
  • packages/ui-kit-chat-tools/tsconfig.json
  • packages/ui-kit-chat/tsconfig.build.json
  • packages/ui-kit-chat/tsconfig.json
  • packages/ui-kit-system/tsconfig.build.json
  • packages/ui-kit-system/tsconfig.json
  • packages/ui-kit-tap/tsconfig.build.json
  • packages/ui-kit-tap/tsconfig.json
  • packages/ui-kit-terminal/tsconfig.build.json
  • packages/ui-kit-terminal/tsconfig.json
  • packages/uno-preset/tsconfig.build.json
  • packages/uno-preset/tsconfig.json
  • packages/vitest-config/tsconfig.json
  • turbo.json

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Makes TypeScript typechecks incremental and allows Turbo to cache their build-info artifacts without build/typecheck write conflicts.

Changes:

  • Enables incremental typechecking across all 50 workspaces.
  • Caches root and nested .tsbuildinfo outputs.
  • Gives declaration builds separate .build.tsbuildinfo files.

Reviewed changes

Copilot reviewed 72 out of 72 changed files in this pull request and generated no comments.

Show a summary per file
File Description
turbo.json Caches typecheck build-info outputs.
packages/vitest-config/tsconfig.json Enables incremental typechecking.
packages/uno-preset/tsconfig.json Enables incremental typechecking.
packages/uno-preset/tsconfig.build.json Isolates build metadata.
packages/ui-kit-terminal/tsconfig.json Enables incremental typechecking.
packages/ui-kit-terminal/tsconfig.build.json Isolates build metadata.
packages/ui-kit-tap/tsconfig.json Enables incremental typechecking.
packages/ui-kit-tap/tsconfig.build.json Isolates build metadata.
packages/ui-kit-system/tsconfig.json Enables incremental typechecking.
packages/ui-kit-system/tsconfig.build.json Isolates build metadata.
packages/ui-kit-chat/tsconfig.json Enables incremental typechecking.
packages/ui-kit-chat/tsconfig.build.json Isolates build metadata.
packages/ui-kit-chat-tools/tsconfig.json Enables incremental typechecking.
packages/ui-kit-chat-tools/tsconfig.build.json Isolates build metadata.
packages/try/tsconfig.json Enables incremental typechecking.
packages/tools/tsconfig.json Enables incremental typechecking.
packages/storage-history/tsconfig.json Enables incremental typechecking.
packages/solid/tsconfig.json Enables incremental typechecking.
packages/solid-streamdown/tsconfig.json Enables incremental typechecking.
packages/solid-streamdown/tsconfig.build.json Isolates build metadata.
packages/solid-diffs/tsconfig.json Enables incremental typechecking.
packages/solid-diffs/tsconfig.build.json Isolates build metadata.
packages/serve/tsconfig.json Enables incremental typechecking.
packages/react/tsconfig.json Enables incremental typechecking.
packages/publish/tsconfig.json Enables incremental typechecking.
packages/protocol/tsconfig.json Enables incremental typechecking.
packages/protocol/tsconfig.build.json Isolates build metadata.
packages/preact/tsconfig.json Enables incremental typechecking.
packages/plugin/tsconfig.json Enables incremental typechecking.
packages/page/tsconfig.json Enables incremental typechecking.
packages/oxlint-plugin/tsconfig.json Enables incremental typechecking.
packages/mascot/tsconfig.json Enables incremental typechecking.
packages/it/tsconfig.json Enables incremental typechecking.
packages/harness/tsconfig.json Enables incremental typechecking.
packages/harness-testkit/tsconfig.json Enables incremental typechecking.
packages/harness-init/tsconfig.json Enables incremental typechecking.
packages/grab/tsconfig.json Enables incremental typechecking.
packages/extensions/whiteboard/tsconfig.json Enables incremental typechecking.
packages/extensions/whiteboard/tsconfig.build.json Isolates build metadata.
packages/extensions/try-it/tsconfig.json Enables incremental typechecking.
packages/extensions/try-it/tsconfig.build.json Isolates build metadata.
packages/extensions/test-runner/tsconfig.json Enables incremental typechecking.
packages/extensions/test-runner/tsconfig.build.json Isolates build metadata.
packages/extensions/terminal/tsconfig.json Enables incremental typechecking.
packages/extensions/terminal/tsconfig.build.json Isolates build metadata.
packages/extensions/tanstack/tsconfig.json Enables incremental typechecking.
packages/extensions/tanstack/tsconfig.build.json Isolates build metadata.
packages/extensions/tanstack/test/host/tsconfig.json Adds nested incremental metadata.
packages/extensions/tanstack/test/host/conciv/tsconfig.json Adds nested incremental metadata.
packages/extensions/recorder/tsconfig.json Enables incremental typechecking.
packages/extensions/recorder/tsconfig.build.json Isolates build metadata.
packages/extensions/page/tsconfig.json Enables incremental typechecking.
packages/extensions/page/tsconfig.build.json Isolates build metadata.
packages/extensions/ios/tsconfig.json Enables incremental typechecking.
packages/extensions/ios/tsconfig.build.json Isolates build metadata.
packages/extension/tsconfig.json Enables incremental typechecking.
packages/extension-testkit/tsconfig.json Enables incremental typechecking.
packages/extension-compiler/tsconfig.json Enables incremental typechecking.
packages/embed/tsconfig.json Enables incremental typechecking.
packages/embed/tsconfig.build.json Isolates build metadata.
packages/db/tsconfig.json Enables incremental typechecking.
packages/core/tsconfig.json Enables incremental typechecking.
packages/contract/tsconfig.json Enables incremental typechecking.
packages/client/tsconfig.json Enables incremental typechecking.
packages/cli/tsconfig.json Enables incremental typechecking.
packages/bundle-size/tsconfig.json Enables incremental typechecking.
e2e/e2e-utils/tsconfig.json Enables incremental typechecking.
apps/storybook/tsconfig.json Enables incremental typechecking.
apps/site/tsconfig.json Enables incremental typechecking.
apps/examples/tanstack-start/tsconfig.json Enables incremental app typechecking.
apps/examples/tanstack-start/conciv/extensions/tsconfig.json Adds nested incremental metadata.
apps/conciv/tsconfig.json Enables incremental typechecking.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@omridevk
omridevk merged commit 04c1331 into main Aug 9, 2026
25 checks passed
@omridevk
omridevk deleted the chore/incremental-typecheck branch August 9, 2026 12:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants