Skip to content

docs(start): clarify verbatimModuleSyntax must be disabled#7806

Open
galaxykhh wants to merge 3 commits into
TanStack:mainfrom
galaxykhh:docs/verbatim-module-syntax-ts6
Open

docs(start): clarify verbatimModuleSyntax must be disabled#7806
galaxykhh wants to merge 3 commits into
TanStack:mainfrom
galaxykhh:docs/verbatim-module-syntax-ts6

Conversation

@galaxykhh

@galaxykhh galaxykhh commented Jul 13, 2026

Copy link
Copy Markdown

Summary

  • Update the React and Solid Build from Scratch guides to explicitly set "verbatimModuleSyntax": false in the example tsconfig.json
  • Clarify that TypeScript's compiler default is still false, while tsc --init (TypeScript 5.9+ and 6.0) generates "verbatimModuleSyntax": true as a recommended option
  • Align the start-counter examples (linked from the React guide) and the Start core skill doc with the same guidance

Problem

The build-from-scratch guides warn that enabling verbatimModuleSyntax can cause server-only code to leak into client bundles, but they:

  1. Do not show how to disable it in the example tsconfig.json
  2. Do not mention that tsc --init now generates "verbatimModuleSyntax": true (tsc --init update microsoft/TypeScript#61813)

This is especially relevant for TypeScript 6 users who run tsc --init before following the guide, since the generated config opts into verbatimModuleSyntax even though the compiler default remains false.

Changes

File Change
docs/start/framework/react/build-from-scratch.md Add "verbatimModuleSyntax": false to example tsconfig; expand NOTE
docs/start/framework/solid/build-from-scratch.md Same
examples/react/start-counter/tsconfig.json Add "verbatimModuleSyntax": false
examples/solid/start-counter/tsconfig.json Same
packages/start-client-core/skills/start-core/SKILL.md Mention tsc --init behavior

Test plan

  • Docs-only change; no runtime code modified
  • Verified example tsconfig.json files remain valid JSON
  • Reviewed rendered NOTE callout for clarity on tanstack.com docs preview (if applicable)

Summary by CodeRabbit

  • Documentation

    • Expanded guidance across React and Solid “build from scratch” and “common mistakes” docs on verbatimModuleSyntax.
    • Clarified that TanStack Start doesn’t support enabling it, and explained that while TypeScript defaults to false, tsc --init may set it to true (TypeScript 5.9+/6.0), so tsconfig.json should explicitly set "verbatimModuleSyntax": false.
  • Configuration

    • Updated React and Solid start-counter example tsconfig.json files to set verbatimModuleSyntax to false.

The build-from-scratch guides only said to keep `verbatimModuleSyntax`
disabled without showing how, and didn't mention that `tsc --init`
(TypeScript 5.9+ and 6.0) now generates `"verbatimModuleSyntax": true`.
Add `"verbatimModuleSyntax": false` to the example tsconfig and clarify
that the compiler default is still `false` while the init template
opts in.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

TanStack Start documentation, skills guidance, and React and Solid counter examples now explicitly configure verbatimModuleSyntax as false and explain its incompatibility with TanStack Start and tsc --init behavior.

Changes

verbatimModuleSyntax configuration

Layer / File(s) Summary
Configuration guidance and examples
docs/start/framework/{react,solid}/build-from-scratch.md, examples/{react,solid}/start-counter/tsconfig.json, packages/start-client-core/skills/start-core/SKILL.md
Documentation and skills guidance explain the required setting, while both counter examples set verbatimModuleSyntax to false.

Estimated code review effort: 1 (Trivial) | ~5 minutes

Suggested labels: documentation

Suggested reviewers: schiller-manuel

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: documenting that verbatimModuleSyntax should be disabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Comment thread docs/start/framework/react/build-from-scratch.md Outdated
Clarify that verbatimModuleSyntax can be used but may leak server-only
code into client bundles when importing types from mixed modules.

Co-authored-by: Cursor <cursoragent@cursor.com>

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/start/framework/solid/build-from-scratch.md`:
- Line 48: Revise the `verbatimModuleSyntax` warning to clarify that only
`import type` statements are elided; inline type-only imports such as `import {
type ... }` still emit an import statement. State that regular imports used for
type-only dependencies from server-only modules can leak server code into client
bundles, while keeping the recommendation to disable the option.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 720056ae-68c9-40f7-8514-ac0bd07320db

📥 Commits

Reviewing files that changed from the base of the PR and between 459f2de and 3162d78.

📒 Files selected for processing (2)
  • docs/start/framework/react/build-from-scratch.md
  • docs/start/framework/solid/build-from-scratch.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/start/framework/react/build-from-scratch.md


> [!NOTE]
> Enabling `verbatimModuleSyntax` can result in server bundles leaking into client bundles. It is recommended to keep this option disabled.
> Enabling `verbatimModuleSyntax` can result in server-only code leaking into client bundles when types are imported from modules that also contain server-only code. It is recommended to keep this option disabled.

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

sed -n '35,60p' docs/start/framework/solid/build-from-scratch.md && printf '\n---\n' && python3 - <<'PY'
import urllib.request
url='https://www.typescriptlang.org/tsconfig/verbatimModuleSyntax.html'
print(urllib.request.urlopen(url, timeout=20).read().decode('utf-8')[:5000])
PY

Repository: TanStack/router

Length of output: 3773


🏁 Script executed:

python3 - <<'PY'
from pathlib import Path
p=Path('docs/start/framework/solid/build-from-scratch.md')
print(p.exists(), p)
PY

Repository: TanStack/router

Length of output: 207


🏁 Script executed:

sed -n '44,52p' docs/start/framework/solid/build-from-scratch.md

Repository: TanStack/router

Length of output: 669


🌐 Web query:

TypeScript verbatimModuleSyntax import type inline type specifiers erased regular imports server-only code

💡 Result:

The verbatimModuleSyntax compiler option in TypeScript (introduced in 5.0) mandates that TypeScript performs no automatic elision (removal) of import or export statements [1][2]. By default, TypeScript heuristically determines which imports are types and removes them during compilation [3][4]. When verbatimModuleSyntax is enabled, TypeScript emits import and export statements exactly as written in the source code [2][5]. Key implications include: 1. Explicit Syntax Requirements: Developers must explicitly use the type modifier for type-only imports and exports (e.g., import type { T } from 'mod' or import { type T } from 'mod') [2][4]. If an import is not marked as type, TypeScript assumes it is a value import and will include it in the emitted JavaScript, regardless of whether it is used only as a type in your TypeScript code [2][5]. 2. Handling Inline Type Specifiers: An important nuance is that when you use inline type specifiers—such as import { type A } from 'mod'—verbatimModuleSyntax ensures the type part is erased, but the import statement itself remains in the emitted code [6]. If an import declaration contains no value imports and only inline type specifiers, the resulting JavaScript will still contain an empty import (e.g., import {} from 'mod'), which effectively functions as a side-effect import [6][7]. 3. Server-Only Code and Runtime Safety: Because verbatimModuleSyntax preserves imports that are not explicitly marked as type-only, it prevents unintentional runtime errors where TypeScript might have otherwise elided an import that was actually needed at runtime [2][5]. Conversely, it can cause issues in environments like Next.js where importing from a server-only module into a client component is strictly prohibited [7]. If you import a type from a server-only file using an import declaration that contains side effects (or is not strictly a type-only import), the build tool may incorrectly flag the file as a client-side dependency, leading to errors [7]. 4. Compatibility with Node.js Type Stripping: As of 2026, verbatimModuleSyntax is recommended when working with modern Node.js environments that support native "type stripping" (or erasable syntax), as it enforces the explicit syntax required for Node.js to safely strip types without breaking runtime code execution [8][9][10].

Citations:


🌐 Web query:

site:typescriptlang.org verbatimModuleSyntax inline type specifiers import {} from module emitted code

💡 Result:

When the verbatimModuleSyntax compiler option is enabled in TypeScript, the compiler adopts a strict policy regarding imports and exports: it does not transform or elide any import or export statements unless they are explicitly marked with the type modifier [1][2]. For imports and exports containing inline type specifiers, the behavior is as follows: 1. Type-only imports and exports: Any import or export statement that exclusively uses the type modifier (e.g., import type { A } from "a") is erased entirely from the emitted JavaScript code [1]. 2. Mixed imports and exports: If an import or export statement contains both value references and type-only references, the statement is rewritten to remove only the type-only parts [1]. 3. Imports and exports that become empty: If an import or export statement consists entirely of type specifiers (or becomes empty after removing those marked with type), the resulting import or export will be emitted as an empty declaration, such as import {} from "xyz" [1]. This behavior ensures that the emitted code remains consistent with the module format specified by your configuration, preventing TypeScript from implicitly rewriting or eliding code in ways that might conflict with your target module system [1][3].

Citations:


🌐 Web query:

TypeScript verbatimModuleSyntax "import { type" emitted import {} from module

💡 Result:

The verbatimModuleSyntax compiler option in TypeScript (introduced in version 5.0) mandates that all import and export statements are emitted exactly as written, with no automatic elision [1][2][3]. Under this setting, TypeScript stops trying to guess whether an import is used as a value or just a type, and instead relies strictly on whether you use the type modifier [2][4]. Regarding the behavior with import { type... } and empty imports: 1. Import Transformation: When you use the type modifier on named imports, TypeScript removes only the type-specific parts during compilation [2]. 2. Emitted Empty Braces: If an import statement consists entirely of type-only named imports, such as import { type T } from "module", TypeScript will rewrite it to import {} from "module" in the emitted JavaScript [5][2]. 3. Why this happens: This behavior is a direct consequence of the verbatim principle—preserving the original module syntax as much as possible [5]. Because the statement was an import declaration, the output retains the import structure even if the named imports are empty, which effectively becomes a side-effect-only import [5][2]. This approach ensures consistency and forces developers to be explicit about their intentions regarding module usage and side effects, rather than having the compiler silently elide code [2][4]. Because it is more predictable and easier to explain, it replaces the older and more complex flags importsNotUsedAsValues and preserveValueImports [6][2].

Citations:


Clarify that only import type is elided. This warning can read as if any type import is safe, but import { type ... } still emits an import statement. Rephrase it to say the issue is using regular imports for type-only dependencies from server-only modules.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/start/framework/solid/build-from-scratch.md` at line 48, Revise the
`verbatimModuleSyntax` warning to clarify that only `import type` statements are
elided; inline type-only imports such as `import { type ... }` still emit an
import statement. State that regular imports used for type-only dependencies
from server-only modules can leak server code into client bundles, while keeping
the recommendation to disable the option.

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