TL;DR
Cannot find module '@vitejs/plugin-react' or its corresponding type declarations (TS2307) in vite.config.ts has two distinct causes. When the package is missing or the editor's TypeScript server holds a stale view, install the package and restart the TS server. When tsc adds the line There are types at … but this result could not be resolved under your current 'moduleResolution' setting, the package is installed and your tsconfig.node.json still uses "moduleResolution": "Node", which ignores package.json exports. Set it to "bundler" on a recent TypeScript.
The error
The question was asked on Stack Overflow by a developer who scaffolded a React + TypeScript project with npm create vite@latest. npm run dev worked without a warning, yet VS Code underlined the first import of vite.config.ts. Run the compiler on the config's own project and you get the same message in text form:
vite.config.ts(1,19): error TS2307: Cannot find module '@vitejs/plugin-react' or its corresponding type declarations.
The line that follows it, if any, tells you which of the two causes you have. That second line is the whole diagnosis, so read it before changing anything.
Why it happens
Two separate programs look at vite.config.ts. Vite loads and runs it, and the Vite features guide is explicit that "Vite only performs transpilation on .ts files and does NOT perform type checking." The editor's TypeScript language service type-checks it, using the compiler options of whichever tsconfig includes the file. That is why the app starts while the editor complains: the runtime and the type checker resolve the import independently.
In a current create-vite project the root tsconfig.json has "files": [] and only references other configs; in projects from older releases it has its own compilerOptions and "include": ["src"]. Either way, the file that owns vite.config.ts is tsconfig.node.json, whose include is ["vite.config.ts"] in the current template and in the old ones. Editing the root file or tsconfig.app.json does not clear this error on its own.
Cause A — the package is not there, or the editor has not noticed it. create-vite asks Install with npm and start now? and, if you decline, only prints the install command. Opening the folder in VS Code before npm install finishes produces TS2307 with no second line. The same happens when the import names a package that is not in devDependencies, for example @vitejs/plugin-react-swc in a project that installed @vitejs/plugin-react, or the reverse. The accepted answer on the Stack Overflow question is simply to restart VS Code, and a third answer restarts only the TypeScript server; both fit a package that landed on disk after the editor had already resolved the import.
Cause B — the package ships its types only through exports. The TypeScript modules reference lists package.json "exports" as unsupported under node10 (the setting formerly called node) and supported under bundler. That became a problem when the plugin changed its manifest. The npm registry shows that @vitejs/plugin-react 4.7.0 still declares main and types, while 5.0.0 declares only exports, and 4.7.0 is the last 4.x release. Meanwhile, projects generated by older create-vite releases kept the old setting: the tsconfig.node.json of create-vite 4.0.0 sets "moduleResolution": "Node" and its package.json pins typescript to ^4.9.3. Upgrade the plugin to 5.x or later in such a project and TypeScript can no longer find dist/index.d.ts, even though it is sitting in node_modules.
The same applies to vite itself from version 8: the registry manifest of vite 7.1.0 has main and types, vite 8.0.0 has neither. On Vite 4 to 7 with a bumped plugin, only the plugin import fails; on Vite 8, both lines of vite.config.ts fail.
Tell the two causes apart
Ask the compiler directly, with the config that owns the file:
npx tsc -p tsconfig.node.json --noEmit
Reproduced with TypeScript 5.9.3, @vitejs/plugin-react 6.1.1 and Vite 8.3.1 under "moduleResolution": "Node", the output carries the tell-tale hint (the path is shortened here):
vite.config.ts(1,19): error TS2307: Cannot find module '@vitejs/plugin-react' or its corresponding type declarations.
There are types at '/app/node_modules/@vitejs/plugin-react/dist/index.d.ts', but this result could not be resolved under your current 'moduleResolution' setting. Consider updating to 'node16', 'nodenext', or 'bundler'.
vite.config.ts(2,30): error TS2307: Cannot find module 'vite' or its corresponding type declarations.
There are types at '/app/node_modules/vite/dist/node/index.d.ts', but this result could not be resolved under your current 'moduleResolution' setting. Consider updating to 'node16', 'nodenext', or 'bundler'.
With a correct bundler setting but an import of a package that is not installed, the error stands alone:
vite.config.ts(1,19): error TS2307: Cannot find module '@vitejs/plugin-react-swc' or its corresponding type declarations.
No hint means Cause A. The hint means Cause B.
Fix for Cause A: install the right package, then restart the TS server
- Check which React plugin the project actually has:
npm ls @vitejs/plugin-react @vitejs/plugin-react-swc
- If the one your
vite.config.tsimports is missing, install it, or change the import to the one that is installed. For the default plugin:
npm install --save-dev @vitejs/plugin-react
For the SWC variant, the plugin-react-swc README installs it with npm i -D @vitejs/plugin-react-swc and imports it as shown here:
import react from '@vitejs/plugin-react-swc'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [react()],
})
- Restart the language service so it resolves the import again: open the Command Palette (
Ctrl+Shift+P, orCmd+Shift+Pon macOS) and runTypeScript: Restart TS server, as the third Stack Overflow answer describes. Restarting the whole editor, the accepted answer, has the same effect.
Fix for Cause B: switch tsconfig.node.json to bundler resolution
- Upgrade TypeScript. The
bundlermode arrived in TypeScript 5.0, so the^4.9.3of the old template cannot use it. In testing, TypeScript 5.0.4 also failed to parse the declaration file of@vitejs/plugin-react6.1.1, while 5.9.3 and 6.0.3 compiled it cleanly. The least disruptive choice for an old project is TypeScript 5.9, which leaves the rest of your config valid:
npm install --save-dev typescript@~5.9.3
If you go to TypeScript 6 instead (typescript@~6.0.2, the range the current template uses), the old template's root tsconfig.json breaks too: it also sets "moduleResolution": "Node" and "esModuleInterop": false, and in testing TypeScript 6.0.3 rejected both with TS5107. In that case set "moduleResolution": "bundler" in the root tsconfig.json (or tsconfig.app.json) as well and delete the "esModuleInterop": false line; with those two changes the same file compiled with no errors.
- Replace
tsconfig.node.jsonwith a version that readsexports. This keeps the old template'scompositeflag, so the project reference in the roottsconfig.jsonstill works, and addstargetandskipLibCheck: without them, the reproduction on TypeScript 5.9.3 failed with TS18028 ("Private identifiers are only available when targeting ECMAScript 2015 and higher") inside the declaration files Vite 8 pulls in from Rolldown.
{
"compilerOptions": {
"composite": true,
"target": "ES2022",
"lib": ["ES2023"],
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true,
"skipLibCheck": true
},
"include": ["vite.config.ts"]
}
If you would rather match a freshly generated project, the current template omits
moduleResolutionand sets"module": "nodenext"instead. Either mode readsexports; the compiler's own hint listsnode16,nodenextandbundleras the settings that work.Make sure the editor uses the project's TypeScript, not the one bundled with VS Code. The VS Code TypeScript documentation notes that the workspace version is independent of the one VS Code ships, and lets you switch through the
TypeScript: Select TypeScript Versioncommand or pin it with thejs/ts.tsdk.pathworkspace setting. Then restart the TS server as in Cause A.
Verify the fix
Run the same command as before:
npx tsc -p tsconfig.node.json --noEmit
It must exit with no output. In the reproduction above, the bundler configuration from step 2 passed on TypeScript 5.9.3 and 6.0.3. Then open vite.config.ts; the underline should be gone once the TS server has restarted. Finally make sure the pipeline runs the same check, not just the editor. The current template's build script is tsc -b && vite build, and -b builds the referenced tsconfig.node.json. The old template's script is tsc && vite build: plain tsc compiles only the root project, which includes src and not vite.config.ts, so a green build proves nothing about this error. In such a project add the explicit check to the script, for example "build": "tsc && tsc -p tsconfig.node.json --noEmit && vite build", or run that command in CI.
TypeScript 6 changes the first error you see
On TypeScript 6, an old "moduleResolution": "Node" no longer reaches TS2307. The compiler stops earlier, at the config:
error TS5107: Option 'moduleResolution=node10' is deprecated and will stop functioning in TypeScript 7.0. Specify compilerOption '"ignoreDeprecations": "6.0"' to silence this error.
The TypeScript 6.0 announcement recommends migrating to nodenext when targeting Node.js directly, or to bundler when using a bundler. Adding "ignoreDeprecations": "6.0" is not a fix here: in testing, it silenced TS5107 and TS2307 came straight back, with the same There are types at … hint, because resolution still ignores exports. The wider list of what 6.0 breaks is in the TypeScript 6.0 migration notes for Next.js and Supabase.
Similar errors that are not this one
TS2307 says the module could not be resolved at all. TS7016, "Could not find a declaration file for module", is a different situation: the JavaScript resolves but ships no types, and the answer there is an @types package or a local declaration. If the import resolves but a specific name is missing, a package's exports map is again a likely culprit, covered under the broken exports map cause of the TS2305 "Module has no exported member" guide. And when it is the Vite build, not the editor, that cannot find a file, the problem is in Rollup's resolution rather than TypeScript's, as in Rollup failing to resolve /src/main.tsx.
The pattern behind all of them is the same: a tool resolves the import with rules different from the ones that installed it. For vite.config.ts, the rules live in tsconfig.node.json, and a project that has upgraded its dependencies but not that file will keep reporting a module that is plainly on disk until its resolution mode catches up with how packages now publish their types.
Originally published at https://www.iloveblogs.blog
Top comments (0)