vitejs / vite
Vite keeps the dev loop short by letting the browser load modules itself
Vite pairs a development server built on native ES modules with a production build that now runs on Rolldown. Nuxt, SvelteKit, Astro and other frameworks use it as their build layer, so understanding its two halves explains a lot of modern frontend behavior, including the moments when development and production disagree.
WHAT TO KNOW FIRST
- In development Vite serves source over native ES modules and pre-bundles dependencies; production builds bundle with Rolldown, which uses Oxc for parsing, transforming and minifying.
- Any VITE_ prefixed variable is bundled into client code, and the docs say such variables should not contain API keys or other secrets.
- Setting server.allowedHosts to true exposes the dev server to DNS rebinding, which the docs warn lets other websites download source code.
01Two halves under one configuration
The Vite README describes two parts: a dev server that adds features on top of native ES modules, including fast Hot Module Replacement, and a build command that bundles code with Rolldown into optimized static assets. The Why Vite page explains the original split. Dependencies, which change rarely, are pre-bundled once. Application source, which changes constantly, is served on demand, so the browser requests only the modules the current page needs and Vite transforms each one when it is requested.
That design keeps startup quick as a project grows, and it is also why development and production are different programs. During development the browser walks the module graph itself; in production the code arrives as bundled chunks. Most of the time the difference is invisible. When it shows, the symptom is a feature that works under the dev server and breaks after a build, usually around dynamic imports, asset URLs or code that assumed modules would evaluate in a particular order.
02Rolldown replaced a two-tool pipeline
Earlier versions used esbuild for fast compilation in development and Rollup for production builds. The Why Vite page says maintaining two pipelines caused inconsistencies in transformation behavior, separate plugin systems and growing glue code. Rolldown, written in Rust and compatible with the existing plugin API, was built to unify them, and it relies on Oxc for parsing, transforming and minifying. The page describes a technical preview, ecosystem CI and a compatibility layer as the way the switch was staged.
For a team upgrading an older project, the practical point is that build output can change even when configuration does not. Chunk boundaries, minified code and the handling of unusual syntax now come from a different engine. Compare bundle sizes and run end-to-end tests against the built output when crossing a major version. The project's stated direction includes a full bundle mode for the dev server, which the docs present as work being explored for very large codebases, not as a shipped default.
03index.html is part of the source
A Vite project keeps index.html at the project root instead of inside a public folder. The getting started guide explains that during development Vite is a server and index.html is the entry point to the application, treated as part of the module graph. Module script tags, inline modules and linked CSS all get Vite's processing, and URLs inside the file are rebased, so placeholder variables are unnecessary. Multi-page apps work by adding more HTML entry points.
This makes the root directory a setting with consequences. Running vite serves the current working directory, an alternative root can be passed on the command line, and the config file is resolved inside that root. In a monorepo, decide which package owns which root and keep those boundaries in the scripts CI runs. A build that picks up the wrong index.html or config file can produce an app that looks right on one laptop and ships the wrong entry point.
04Plugins carry much of the behavior
Vite's plugin API follows Rollup's conventions, which the Why Vite page credits for making framework integration natural. Nuxt, SvelteKit, Astro, React Router, Analog and SolidStart build on it, tools such as Vitest and Storybook extend it beyond app bundling, and backend frameworks including Laravel and Ruby on Rails use it for their frontend assets. The Vite team runs vite-ecosystem-ci, which tests major downstream projects against each change before release.
Every plugin runs inside the build with access to source files and the module graph, so it belongs in the same review as any dependency that shapes production output. Keep the plugin list short, pin versions in the lockfile and check that each plugin supports the Vite major in use. When something breaks after an upgrade, removing plugins one at a time is often the quickest diagnosis, because framework plugins carry much of the behavior that looks like Vite's own.
05Environment variables reach the browser by design
Vite exposes constants on import.meta.env and replaces them statically at build time. Variables prefixed with VITE_ are exposed to client code after bundling, and the env and mode page is direct about the consequence: VITE_ variables should not contain sensitive information such as API keys, because their values are bundled into the source. The prefix can be changed with the envPrefix option, and values parsed from .env files arrive as strings, so numbers and booleans need converting.
Treat the prefix as a publishing decision. Anything that carries it should be safe to show on a public page, because in effect it will be. Keys for paid APIs, database credentials and signing secrets belong on a server or in a serverless function the client calls. A useful pre-deploy check is to search the built assets for known secret patterns, since a renamed variable or a changed envPrefix can move a value into the bundle without any other warning.
06The dev server is not a public server
server.host defaults to localhost; setting it to 0.0.0.0 or true listens on all addresses, including LAN and public ones. server.allowedHosts lists the hostnames Vite will respond to, with localhost, domains under .localhost and all IP addresses allowed by default. The server options page warns that setting allowedHosts to true lets any website send requests to the dev server through DNS rebinding and download source code and content, and it links a published security advisory on the subject.
The usual route into trouble is a tunnel or a shared preview, where someone sets allowedHosts to true because a hostname was rejected. Add that one hostname instead, and only hostnames whose DNS you control; the docs specifically warn against adding a top-level domain. Leave server.fs.strict on, since it limits which files can be served through the file system route. For anything other people need to reach for more than a quick look, deploy the built output to a real host.
- Keep server.host at localhost unless another device on a trusted network must reach the dev server.
- List tunnel or preview hostnames explicitly in server.allowedHosts instead of setting it to true.
- Never treat a running dev server as a staging environment for outside users.
07Browser targets and upgrades
Each Vite major fixes its browser assumptions to a date. For the current major, runtime code injected by the dev server uses features that were Baseline Newly Available as of 2026-01-01, while production builds by default target Baseline Widely Available browsers from around mid-2023. The target can be lowered in configuration, and the official @vitejs/plugin-legacy package covers older browsers. Node.js 20.19+ or 22.12+ is required. The GitHub releases API showed v8.3.5, published October 21, 2026, as the latest release when this guide was checked.
Read the release notes and the changelog before moving between majors, and plan the upgrade around the plugins as much as around Vite itself. Lock the version, upgrade on a branch, run the production build and the test suite, and compare bundle output and browser support with the previous release. To try an unreleased fix, the guide documents installing a specific commit through pkg.pr.new and notes that only commits from roughly the last month remain available.
08When Vite is the right base
Vite fits most new single-page apps, component libraries and multi-page sites, and it already sits underneath many meta-frameworks, so teams often adopt it without choosing it directly. Its strength is a short loop between saving a file and seeing the change, plus a production build that needs little configuration for common cases. The repository is MIT licensed, and the packages it publishes include vite, create-vite and @vitejs/plugin-legacy.
It is less suited to builds that are mostly custom: unusual asset pipelines, toolchains that need byte-level control of output, or legacy code that depends on quirks of an older bundler. Those can work through plugins, but the effort moves from configuration into maintenance. Evaluate on a real branch with the production build and the heaviest page, not on a starter template, because templates rarely reveal where a build tool's assumptions stop matching the code.
A SENSIBLE FIRST HOUR
Start small enough to learn the repo
- Check Node.js against the guide's requirement (20.19+ or 22.12+), then scaffold with npm create vite@latest and follow the prompts, or name a template directly, for example npm create vite@latest my-vue-app -- --template vue.
- Start the dev script, open http://localhost:5173, edit a component and watch the hot update, then open the browser's network panel to see source modules requested one by one.
- Run the build and preview scripts (vite build and vite preview) and compare the built app with the dev server: routes, asset paths, environment variables and dynamic imports.
- Before adding plugins, read the env and server options pages: keep secrets out of VITE_ variables and keep server.allowedHosts as an explicit list of hostnames you control.
SOURCE LEDGER
What this review is built on
We use the project repository and first-party documentation. Access, licenses and project direction can change, so recheck the linked source before making a production decision.