TypeScript

Fix Vite "Cannot find package vite" in vite.config.ts

Why vite vanishes from node_modules after a clean install, reproduced on npm 9.5.0 and Node 18 with a global vite install, plus the extra step the fix needs to outlast the next npm install.

Mahdi Ben RhoumaMahdi Ben Rhouma
7 min read

TL;DR#

npm create vite@latest puts vite itself, its framework plugin and TypeScript under devDependencies — only react and react-dom land in dependencies. If npm install runs while the NODE_ENV environment variable is already production, or with --omit=dev (or the deprecated --production flag), npm skips devDependencies on purpose: vite is resolved into the lockfile but never written to node_modules, so the dev server and the build both fail. Run npm install --include=dev to get it back, then find and remove whatever set NODE_ENV=production in the first place — otherwise the next plain npm install repeats the exact same failure.

A developer hit this with the default React + TypeScript template and reported the exact output below:

text
> vite-react@0.0.0 dev
> vite
 
failed to load config from [my-path]\vite-project\vite-react\vite.config.ts
error when starting dev server:
Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'vite' imported from [my-path]\vite-project\vite-react\vite.config.ts.timestamp-1677228345613.mjs
    at new NodeError (node:internal/errors:399:5)
    at packageResolve (node:internal/modules/esm/resolve:889:9)
    at moduleResolve (node:internal/modules/esm/resolve:938:20)
    at defaultResolve (node:internal/modules/esm/resolve:1153:11)
    at nextResolve (node:internal/modules/esm/loader:163:28)
    at ESMLoader.resolve (node:internal/modules/esm/loader:838:30)
    at ESMLoader.getModuleJob (node:internal/modules/esm/loader:424:18)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:77:40)
    at link (node:internal/modules/esm/module_job:76:36)

(reported on Node v18.14.2, npm 9.5.0, vite/4.1.1. The same report says a plain Vanilla + TypeScript project on the same machine worked, even though its package.json also lists vite only under devDependencies — the report does not say whether that install kept its devDependencies or avoided this failure some other way; the accepted answer below only establishes that this project's install dropped them.)

Check your own ERR_MODULE_NOT_FOUND#

Paste the exact error Node.js printed for your own project — this runs in your browser, nothing is sent anywhere.

Runs entirely in your browser — nothing you paste is sent anywhere. Tokens and passwords that appear in paths or URLs are masked in the output.

Optional: package.json, file extension, Node.js version (sharper advice)
Try:

If it tells you to run npm ci, add --include=dev to that too while NODE_ENV=production is set: npm ci reconciles node_modules with the lockfile under the same omit rule as npm install, so it skips devDependencies for the same reason.

Why it happens#

Run npm create vite@latest today and pick the React + TypeScript template: the generated package.json still puts vite, @vitejs/plugin-react, typescript and the @types/* packages under devDependencies, next to react and react-dom in dependencies — the exact shape of the package.json pasted in the original report, only with newer version numbers.

npm decides which dependency types to physically write to disk with its omit config. Its default is not fixed — it depends on the environment the moment npm install runs. From npm's own source, unchanged in substance from the reporter's npm 9.5.0 to today's npm 12:

text
define('omit', {
  default: process.env.NODE_ENV === 'production' ? ['dev'] : [],
  ...
  description: `
    Dependency types to omit from the installation tree on disk.
 
    Note that these dependencies _are_ still resolved and added to the
    package-lock.json or npm-shrinkwrap.json file. They are just
    not physically installed on disk.
    ...
    If the resulting omit list includes 'dev', then the NODE_ENV
    environment variable will be set to 'production' for all lifecycle
    scripts.
  `,
  ...
})

(condensed: ... marks omitted lines, and the escaped backticks the real source uses around code names inside its template-literal description are removed here for readability; nothing in the quoted wording itself is changed. npm/cli lib/utils/config/definitions.js, tag v9.5.0, unchanged at the current tag; documented the same way on npm's own config reference.) In plain terms: if NODE_ENV is already production when npm install runs — from a stray environment variable, an .npmrc with production=true or omit=dev, or the explicit --omit=dev / deprecated --production flag — npm quietly leaves every devDependency out of node_modules. vite is a devDependency, so it is one of the packages left out, and so is @vitejs/plugin-react.

The accepted answer on the original report reached the same conclusion from the other direction, after first trying a workaround:

text
UPDATE, SOLUTION:
 
`npm install --include=dev`
 
well not a solution to the root cause but works.
 
And the actual root cause was:
 
`npm install` did not install the devDependencies in the automatically generated `package.json` by default...

Reproduced: on npm 9.5.0 / Node 18.20.8, installing the reporter's own package.json with NODE_ENV=production set (so the local devDependencies, vite included, are skipped) reproduces the same three lines as the report — "failed to load config from …", "error when starting dev server:", and the Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'vite' imported from …timestamp-*.mjs line, with the container's path and timestamp standing in for the reporter's — but only once a vite binary exists somewhere else that the shell can still reach (a global npm install -g vite, in this run). npm run dev runs the project's dev script, vite, and npm adds the project's own node_modules/.bin to PATH for that script; when vite is missing there, the shell falls through to the rest of PATH and finds the global one instead — but only until the local copy exists again: after npm install --include=dev, the same npm run dev started VITE v4.5.14, the version the project's vite@^4.1.0 resolved to, not the globally installed 4.1.1 (both logged in repro.log), so the local node_modules wins once it is there. That global vite starts, and both the dev server's createServer and build call resolveConfig, which calls loadConfigFromFile — the same path either way. For an ESM project, loadConfigFromFile bundles vite.config.ts, and a source comment calls what follows a hack: "write it to disk, load it with native Node ESM, then delete the file" (config.ts#L1065-L1069), named <file>.timestamp-<epoch>.mjs. That temporary file's import … from "vite" still has to resolve against the project's node_modules — where the package is still missing — so it throws ERR_MODULE_NOT_FOUND instead of the plainer sh: vite: not found a project with no vite anywhere at all would print. The report does not say whether a global Vite was the exact reason in this case; what it confirms is only that npm install skipped the project's devDependencies.

Fix#

  1. Find out why devDependencies are being skipped, so the fix outlasts this one install. Check the environment variable and the four .npmrc files npm reads — a project file, a per-user file ($HOME/.npmrc), a global file, and npm's own built-in config file:

    bash
    echo $NODE_ENV           # macOS/Linux/WSL shell
    npm config list -l | grep -i "omit\|production"
    powershell
    $env:NODE_ENV             # PowerShell, on the reporter's own OS

    A NODE_ENV set through Windows' System Properties → Environment Variables (or an old setx NODE_ENV production) persists across every new terminal until it is removed there. A plain export NODE_ENV=… typed directly into one Linux/macOS shell does not outlive that shell, but the same line sitting in a ~/.bashrc or ~/.zshrc runs again for every new terminal too, so check those as well before assuming the cause was a one-off.

  2. Install the missing devDependencies now:

    bash
    npm install --include=dev

    --include=dev overrides the omit default for this one run, regardless of what set it. Reproduced on npm 9.5.0 with the reporter's own package.json: a plain npm install while NODE_ENV=production added 5 packages and left vite out; npm install --include=dev right after added 56 more, including vite itself.

  3. Remove the cause, not just the symptom. Unset the stray NODE_ENV, delete the production=true or omit=dev line from whichever .npmrc step 1 found, or stop passing --omit=dev / --production. Skip this step and the fix looks like it "stops working" later: a teammate's fresh clone, a CI cache rebuild, or your own next rm -rf node_modules && npm install reads the exact same leftover config and reproduces the failure from scratch, because a plain npm install still honours it.

  4. In Docker or CI, do not blanket-unset it. A Dockerfile with ENV NODE_ENV=production set before RUN npm install, or a deploy step that exports the same variable on purpose, is correct for the dependencies a running backend needs — that part should stay. A Vite front end still needs its build step, which needs vite, a devDependency, to run before that backend ever serves anything, so only that one step needs npm install --include=dev (or npm ci --include=dev) even in an otherwise production build.

Verify the fix#

With vite back in node_modules, the same project — global vite installed or not — starts cleanly:

text
> vite-react@0.0.0 dev
> vite
 
  VITE v4.5.14  ready in 1035 ms
 
  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose

(reproduced on Node 18.20.8 / npm 9.5.0 / the reporter's 2023 package.json, 26 October 2026 — vite@^4.1.0 resolved to 4.5.14, the newest release still satisfying that range.) vite build loads vite.config.ts the same way vite (dev) does, so a stuck production build is the same check: confirm vite is a real directory under node_modules, not just listed in package.json.

If your editor also underlines the @vitejs/plugin-react import in vite.config.ts, check which case you are in. With devDependencies skipped, @vitejs/plugin-react is missing too — the same root cause as this page, just reported by the editor instead of node, and fixed by the same npm install --include=dev. A TS2307 that survives that install, with the dev server running fine, is a different bug: see Fix Cannot find module '@vitejs/plugin-react' in Vite for the tsconfig.node.json resolution case, where the package is already on disk and only the editor's module resolution is wrong.

One email a month — the latest explained errors

What the site published that month — mostly Next.js, Supabase and Node errors, explained. You confirm by email; unsubscribe any time in one click.

In Docker, tell this apart from two other Vite failures#

If this project is built inside Docker, a line such as ENV NODE_ENV=production applies to every instruction that follows it in that build stage — including a RUN npm install placed after it to build the front end, even when the variable was only meant to describe the final, deployed image. Two other Vite-in-Docker failures look superficially similar but need a different fix, so it is worth telling them apart before assuming this article covers a container error too: a bind mount that brings a host node_modules built for the wrong OS/CPU into the container fails on the native esbuild binary, not on a missing vite (see Fix "esbuild-linux-64" could not be found: Vite in Docker), and a .dockerignore that excludes index.html fails at the bundler's entry point, with vite present and working (see Vite entry module (index.html): fix .dockerignore). If the error names vite itself and ERR_MODULE_NOT_FOUND or "not found", the devDependency fix above is the one that applies.

A later failure, unrelated to installation, can show up at build time once npm run dev itself is fixed. Vite's dev server transpiles TypeScript on the fly and does not check which browsers the result has to run in; vite build does check, against build.target, and can reject code the dev server let through silently — your own module's top-level await is one documented case (a dependency's top-level await is different: Vite's dev pre-bundler checks dependencies too, so that case can fail in dev as well). If dev now works but build stops with a different, unrelated-looking error, that is a separate, already documented failure: see Fix Vite 'Top-level await is not available' build error.

Further reading: Vite linked React library: fix Invalid hook call.

Frequently Asked Questions

|

Have more questions? Contact us

Still stuck? Paste your error.

Paste the error message or stack trace — we check it against every fix and tool on the site.

Matching happens in your browser. When you search, a cleaned error signature is sent so we can spot errors we do not cover yet — never the raw text, your IP address or your e-mail. Do not paste passwords or keys. Details

Written by

Mahdi Ben Rhouma
Mahdi Ben Rhouma

Full-Stack Dev — Next.js & Supabase

Solo developer building SaaS products with Next.js and Supabase. Writing about production patterns the official docs skip.

Remote