OMAR
Field NotesCV
Vite: Why the Dev Server Feels Instant
← All Notes
Tooling06 August 2026 · 3 min read

Vite: Why the Dev Server Feels Instant

It does not bundle during development. Understanding that one decision explains the speed, the plugin model, and the two places it still surprises people.

Every bundler-based dev server does the same thing on startup: read your entire dependency graph, transform it, bundle it, then serve it. The cost scales with project size, which is why the third year of a codebase starts with a coffee break.

Vite's development server does not bundle. Browsers support ES modules natively, so it serves your source files directly and transforms each one on request.

The consequence is that startup time is roughly constant. A twenty-file project and a two-thousand-file project both start in about the same time, because neither one required the whole graph to be processed first.

Hot updates are proportional to the edit

Change one component and the server invalidates that module and its importers. Not the bundle — the module. The browser fetches the new version and swaps it. This is why HMR stays fast in a big app instead of degrading as the app grows.

Dependencies get special treatment

Your node_modules are not served file-by-file — some packages ship hundreds of tiny modules and that would mean hundreds of requests. They are pre-bundled once with esbuild and cached:

export default defineConfig({
  optimizeDeps: {
    include: ['some-cjs-package'],   // force pre-bundling
    exclude: ['my-local-linked-lib'] // keep a linked package live
  },
})

This is the setting you reach for when a linked local package will not hot-reload, which is the most common "why is Vite being weird" question.

Production does bundle

This is the trap. Development is unbundled; production goes through Rollup. So a difference between dev and build is not a mystery — it is two different code paths, and the one users get is the second one.

Practical rule: run vite build && vite preview before you believe anything about performance, and put the built output — not the dev server — in front of Lighthouse.

Keeping the output honest

build: {
  rollupOptions: {
    output: {
      manualChunks: {
        vendor: ['react', 'react-dom'],
      },
    },
  },
  chunkSizeWarningLimit: 600,
}

Splitting the framework from application code means a content change does not invalidate the cached vendor chunk. And read the size table Vite prints after every build — it is the cheapest performance monitoring available, and it is already in your terminal.

Why it is the default now

The speed is what people talk about, but the durable advantage is that the plugin API is shared with Rollup, so the ecosystem is one ecosystem. Framework choice stopped requiring a bespoke build setup, which is the kind of consolidation that makes every project after it cheaper.

Resources

BuildPerformanceVite

Need this built properly?

I build secure, fast, bilingual platforms for clients across Egypt, Saudi Arabia, the UAE and Kuwait.

Keep Reading