localhost:5173 / optimize-deps
Dependency pre-bundling on the Vite dev server
Vite converts your dependencies to ESM once before serving them on 5173 and caches the result in node_modules/.vite — optimizeDeps controls what goes into that step and what stays out of it.
Why the step exists at all
Two reasons, both about the browser. Packages shipped as CommonJS cannot be imported natively, so they have to be converted. And a package split into many small modules would otherwise become one request per module — lodash-es alone has over 600 internal modules. Pre-bundling collapses that into a single request.
Where the result is cached
In node_modules/.vite. Vite keys that cache to the lockfile content, the modification time of the patches directory, the relevant fields of your config and the value of NODE_ENV. Change any of them and the next start re-bundles. Nothing else invalidates it — which is exactly why a hand-edited package inside node_modules keeps serving the old code.
Discovery, and the reload it causes
Vite crawls your entry points at startup to find bare imports and pre-bundles what it finds. An import that only appears later — behind a dynamic import, in a route you open after the server started — is discovered at that moment. Vite then re-runs the bundling and reloads the page if it has to. That mid-session reload is normal, not a bug.
The options, with their defaults
Only two of them are needed regularly. The rest exist for specific situations and are better left alone.
export default {
optimizeDeps: {
// pre-bundle something the crawler cannot see
include: [], // default: []
// keep something out of the step
exclude: [], // default: []
entries: undefined, // default: inferred from .html or input
force: false, // default: false
noDiscovery: false, // default: false
holdUntilCrawlEnd: true, // default: true
needsInterop: [] // default: []
}
}When to use include
When a dependency is not reachable by crawling your source. A linked package outside node_modules is the standard case: it is not a bare import from the registry, so the crawler skips it, and the browser then requests its internals one file at a time. Listing it in include puts it back into the step.
When to use exclude
When a package must stay as it was published. Packages that ship their own ESM and reference files relative to themselves, or that you are actively editing in another checkout, belong here. Excluding a large CommonJS package is not a speed-up — it moves the conversion cost into the browser.
Errors that come from this step
- A named import from a CommonJS package is undefined at runtime — the interop guess was wrong, try needsInterop.
- The browser loads an old version of a package you just patched — the cache key did not change, re-bundle with --force.
- Stack traces pointing inside node_modules/.vite/deps — the pre-bundle is stale, not your code.
- A linked package produces hundreds of requests in the network tab — it was never pre-bundled, add it to include.
Forcing the step to run again
The flag makes the optimizer ignore the cache. It is the same effect as deleting the directory, and it is the first thing to try when the browser is serving something that no longer exists on disk.
$ npm run dev -- --forceesbuildOptions is deprecated
The optimizer now runs on Rolldown, and rolldownOptions replaced esbuildOptions. Configuration copied from an older answer may still set the old field. It is not an error you will see — it is simply ignored, which is worse, because the setting you wanted never applies.
# faq
Questions
What does optimizeDeps actually do?
It converts dependencies to ESM and bundles each package into one module before the dev server serves them, so the browser makes one request instead of hundreds.
Why does Vite reload the page in the middle of a session?
Because it found a dependency that was not visible when it crawled at startup. It re-runs the bundling and reloads if it needs to.
Do I need to configure optimizeDeps at all?
Usually not. include for linked packages the crawler cannot see, exclude for packages that must stay as published. Everything else is situational.
How do I clear the pre-bundle?
Start with --force, or delete node_modules/.vite. Both rebuild it on the next start.
Is optimizeDeps used in the production build?
No. It is a dev-server step. The build has its own bundling.
# next
Related
# sources
Checked against the Vite documentation on 2026-09-11.