Production builds and deployment

Vite · Practical · 15 min

The build output is what users actually download.

vite build produces a static dist/ folder: the rewritten index.html, and assets/ with content-hashed JS, CSS and asset files (index-D0ftifMV.js). Hashes change only when content changes, so you can serve assets/ with long-lived immutable caching and only index.html with no-cache.

What happens during the build:

  • Bundling and tree-shaking with Rolldown; unused exports are dropped.
  • Code splitting: each dynamic import() becomes a separate chunk loaded on demand. Shared modules are extracted into common chunks, and Vite preloads a chunk's dependencies in parallel.
  • Minification with Oxc (JS) and Lightning CSS (CSS). CSS is extracted per chunk.
  • Syntax lowering to build.target, by default 'baseline-widely-available' (browsers that have supported a feature for about 30 months). Vite does not add polyfills; use @vitejs/plugin-legacy for old browsers.

Useful options: build.sourcemap (true, or 'hidden' to upload to an error tracker without exposing them), build.outDir, build.assetsInlineLimit, and build.chunkSizeWarningLimit (the "chunk larger than 500 kB" warning).

Deploy dist/ to any static host (Netlify, Vercel, Cloudflare Pages, GitHub Pages, S3 + CDN, Nginx). For client-side routers, configure the host to fall back to index.html for unknown paths. If the app lives under a sub-path, set base.

Example

// src/main.js
document.querySelector("#report").addEventListener("click", async () => {
  const { renderReport } = await import("./report.js"); // separate chunk
  renderReport();
});

// $ npx vite build
// dist/index.html                 0.46 kB
// dist/assets/index-9oG4hv_R.css  4.10 kB
// dist/assets/report-cMxiPVRj.js 31.80 kB  <- loaded only on click
// dist/assets/index-D0ftifMV.js  52.70 kB
// built in 640ms

// Caching headers for a CDN or Nginx:
//   /assets/*     Cache-Control: public, max-age=31536000, immutable
//   /index.html   Cache-Control: no-cache

Remember

  • Output is static: hashed assets plus index.html
  • Dynamic import() creates on-demand chunks
  • Default target is baseline-widely-available; no automatic polyfills
  • Cache assets forever, never cache index.html

Watch out for

  • Caching index.html for a long time, so users keep loading old asset hashes after a deploy.

Check yourself

  1. Why can files in dist/assets be cached for a year?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: vite.dev/guide/build