Vite's dev server and its Rolldown build are two different pipelines
Vite provides a fast development server and a production bundler for modern web projects.
At a glance
- What is it?
- Vite is usually described as a bundler, but it is two things: a dev server that serves native ES modules, and a build command that bundles with Rolldown. That split explains most of what surprises people, including why a bundled dev mode is tested separately and why npm install fails on purpose.
- Who is it for?
- Vite suits a team building a modern web app that wants a dev loop close to the browser's own module semantics and a typed plugin API to extend it, and the two published packages beyond the core, `@vitejs/plugin-legacy` and `create-vite`, cover the two cases that come up most. Two things to check before you commit.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 5 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 25, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The dev server serves native ES modules, the build bundles with Rolldown
Vite is described in its own README as two major parts, and they are not the same technology. The first is a dev server that layers feature enhancements over native ES modules, the mechanism Hot Module Replacement is built on. The second is a build command that bundles your code with Rolldown, pre-configured to emit optimized static assets for production.
The name is the French word for quick, and the pitch is a faster, leaner development experience for modern web projects. What matters for an adopter is that the fast path in development is not a bundle at all. Your browser resolves the module graph itself, the way it would for any ES module application, and the dev server is in the middle adding invalidation, transformation and HMR rather than packaging.
Extensibility is the other half of the story, through a Plugin API and a JavaScript API, both with full typing support, and the feature list names a universal plugin interface and fully typed APIs as goals rather than aspirations. So the extension surface is a typed contract, which is the reason Vite plugins tend to compose with each other instead of colliding.
npm install fails on purpose, because of one preinstall line
The monorepo root declares one preinstall script and it is there purely to refuse your package manager:
"preinstall": "npx only-allow pnpm",The repository is a pnpm workspace, with `pnpm-workspace.yaml` and `pnpm-lock.yaml` at the top level, and the hook makes that policy enforceable rather than aspirational. Running `npm install` in a Vite repository fails before a single dependency is resolved.
The consequence is a confusing first error for anyone arriving from an npm background, because the failure is a preinstall hook rather than a resolution problem, and the message names a package manager policy instead of a dependency. It also removes an option you might have wanted. If your organisation standardises on npm, or you are contributing to a project whose lockfile is npm-based, you cannot consume Vite from a Vite checkout without changing the policy, which means your fork now carries a divergence from upstream. Working in a pnpm repository is not a detail here, it is the condition of using the source.
For most users this never comes up, because you install the published `vite` package rather than cloning the monorepo, and the hook lives in the private root package named `@vitejs/vite-monorepo`.
The Node range has a gap in the middle of the 22 line
The root package declares its runtime requirement in a form that is easy to read past:
"engines": {
"node": "^20.19.0 || >=22.12.0"
},Two ranges, not one. The first admits 20.19 and anything above it in the 20 line. The second admits 22.12 and everything later. What it does not admit is the whole span of Node 22 before 22.12, and Node 21 entirely.
Excluding 21 is unremarkable, since it was never a long-term support release. Excluding 22.0 through 22.11 is a different kind of rule, because that is a released LTS line and a container image pinned to 22.11 is an entirely reasonable thing to have. The floor is presumably tied to something the runtime relies on, and 22.12 is one of those minor releases that moves a bundled dependency rather than an API.
The consequence shows up at install rather than at run, and it shows up on a machine rather than in your code. A base image that has not been rebuilt in a while will fail the engines check on a clean install, and nothing about the failure points at the version range as the cause. Check the Node version of your CI image against that floor before you wire Vite into a pipeline, because the fix is a base image bump and it is much cheaper to make deliberately.
Bundled dev is tested separately because it behaves differently from native ESM
The test scripts show how seriously the project treats the gap between the two halves:
"test": "pnpm test-unit && pnpm test-serve && pnpm test-build",
"test-serve": "vitest run -c vitest.config.e2e.ts",
"test-build": "VITE_TEST_BUILD=1 vitest run -c vitest.config.e2e.ts",Note what the last two have in common: the same config file, `vitest.config.e2e.ts`, with the mode selected by an environment variable rather than by a separate config. There is a third variant too, `test-serve-bundled`, which sets `VITE_TEST_BUNDLED_DEV=1` to run the same e2e config with the dev server in bundled mode.
That third suite is the interesting one. It exists because a bundled dev server is not the same as serving native ES modules, and if it were, the suite would not need to exist as a distinct pass. This is the structural cost of the design: development and production are different pipelines, so a difference in how a module resolves, how a dependency is transformed, or how a chunk boundary falls can pass your entire dev loop and only appear in the build output.
The practical consequence is that the dev server cannot be treated as a preview of production. Run the build, and treat the bundled dev suite as a separate environment you can reproduce when something behaves differently between the two. The debugging scripts in the same file reflect that awareness, with `debug-build` setting `VITE_PRESERVE_BUILD_ARTIFACTS=1` so a failed build leaves its output behind for inspection.
vitest run on its own only runs the unit suite
The default test command is a chain of three, and only the first is what most people type. `pnpm test` runs the unit suite, then the serve suite, then the build suite. `vitest run` on its own is `test-unit` and stops there.
The unit suite is the only one that uses the default `vitest.config.ts`. The other two share `vitest.config.e2e.ts` and differ only by the `VITE_TEST_BUILD` environment variable, which is how a single config file serves two different execution modes. That is tidy, and it has a cost: the mode is invisible in the command line, so it lives entirely in the script definition and in whatever sets the variable in your shell.
If you have `VITE_TEST_BUILD=1` exported in a terminal, or a CI job that sets it for one step and forgets to unset it, a later `pnpm test-build` in the same shell is running the build suite twice rather than once. The reverse mistake is quieter: a `pnpm test` run in a dirty shell does not tell you in its output which mode a given pass used, because the mode is not part of what gets printed. There is a separate `test-docs` that builds the documentation site, and `ci-docs` chains the build with the docs build, so publishing also typechecks and builds everything first.
playground/ holds the fixtures, and the formatter is oxfmt with a clean blame
Two details in the top-level layout explain how the project tests itself. There is a `playground/` directory, which is where fixture applications live so that behaviour can be exercised against real projects rather than mocks, and there is `.git-blame-ignore-revs`, a file that tells Git to skip specific commits when attributing blame.
The second one only makes sense alongside the third. Formatting runs through `oxfmt` via a `format` script, with configuration in `.oxfmtrc.json`, and linting runs through ESLint with `eslint.config.js` and a cache. So the codebase is machine-formatted, which means formatting commits are frequent and large, and without the blame ignore list every line in the project would appear to be written by whoever last reformatted it. `.git-blame-ignore-revs` is what keeps `git blame` usable on a repository that formats itself automatically.
The consequence for a contributor is that you accept the formatter's output rather than negotiating it, and that a change touching formatting and behaviour should be two commits. There is also a `patches/` directory, which is where pnpm patch overrides live for fixing a dependency in place, and release chores are scripted, with `ci-publish` running `scripts/publishCI.ts` and changelog merging handled by `scripts/mergeChangelog.ts`. The three published packages are `vite`, `@vitejs/plugin-legacy` for older browser targets, and `create-vite`.
Editorial conclusion
Vite suits a team building a modern web app that wants a dev loop close to the browser's own module semantics and a typed plugin API to extend it, and the two published packages beyond the core, `@vitejs/plugin-legacy` and `create-vite`, cover the two cases that come up most. Two things to check before you commit. The `engines` field is `^20.19.0 || >=22.12.0`, which excludes a slice of the Node 22 line your CI image may be pinned to, and the repository is pnpm-only, enforced by a preinstall hook. If either is a problem where you work, solve it before scaffolding rather than after, because both fail at install time.
Frequently asked questions
What is vitejs used for?
Vite is a TypeScript build tool for modern web projects consisting of two parts: a dev server that adds feature enhancements over native ES modules, including Hot Module Replacement, and a build command that bundles with Rolldown into optimized static assets. It is extended through a Plugin API and a JavaScript API, both with full typing support.
Is Vite replacing Webpack?
The repository does not document a comparison with Webpack. What it states about itself is the two-part design, a native ES module dev server plus a Rolldown production build, and the three packages it publishes: vite, @vitejs/plugin-legacy and create-vite.
Is Vite better than React?
They are not alternatives, because they sit at different layers. Vite is a build tool and dev server, and React is a UI library, so a project commonly uses both: React for components and Vite to serve and bundle them. The Vite repository also ships a separate plugin package for React integration outside its own three published packages.
Is Vite the same as npm?
No. npm is a package manager, and Vite is a build tool that you install with a package manager. Inside the Vite monorepo the distinction is enforced: a preinstall hook runs npx only-allow pnpm, so npm install fails by design and the repository is a pnpm workspace with pnpm-workspace.yaml and pnpm-lock.yaml.
What is the difference between vite and vitejs?
They are the same project, referred to two ways. The npm package you install is named vite, while the GitHub organisation and the monorepo root package are vitejs and @vitejs/vite-monorepo respectively, with the plugin packages prefixed @vitejs/ as well, for example @vitejs/plugin-legacy.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/vitejs-vite)