Vite’s preview command doesn’t actually run your dev server; it serves your production build, which is the most surprising thing about it.
Let’s see it in action. Imagine a simple Vite project with React.
npm create vite@latest my-preview-app --template react
cd my-preview-app
npm install
Now, let’s add a simple component:
src/App.jsx
import { useState } from 'react'
import reactLogo from './assets/react.svg'
import './App.css'
function App() {
const [count, setCount] = useState(0)
return (
<>
<div>
<a href="https://vitejs.dev" target="_blank">
<img src="/vite.svg" className="logo" alt="Vite logo" />
</a>
<a href="https://react.dev" target="_blank">
<img src={reactLogo} className="logo react" alt="React logo" />
</a>
</div>
<h1>Vite + React</h1>
<div className="card">
<button onClick={() => setCount((count) => count + 1)}>
count is {count}
</button>
<p>
Edit <code>src/App.jsx</code> and save to test HMR
</p>
</div>
<p className="read-the-docs">
Click on the Vite and React logos to learn more
</p>
</>
)
}
export default App
After running npm run build, Vite creates a dist folder containing optimized assets. The preview command then uses a minimal, production-ready server to serve the contents of this dist folder.
npm run build
npm run preview
You’ll see output like this:
Vite v5.2.10 preview server running at:
> Local: http://localhost:4173/
> Network: http://192.168.1.10:4173/
Ready in 31ms.
Navigating to http://localhost:4173/ in your browser shows your application, but it’s crucial to understand that this isn’t the same environment as npm run dev. The dev server (npm run dev) is optimized for fast development with features like Hot Module Replacement (HMR) and detailed error overlays. The preview server, on the other hand, serves the exact same files that would be deployed to production. This means:
- Bundling and Optimization: Your code is minified, treeshaken, and bundled according to your
vite.config.jssettings. - Asset Handling: Images, fonts, and other assets are processed, hashed for cache busting, and placed in the
distdirectory. - No HMR: Changes you make to your code won’t be reflected live without a full rebuild and restart of the preview server.
- Production-like Performance: You get a realistic sense of how your application will load and perform in a production environment.
The preview command is powered by preview.port in your vite.config.js for configuration.
vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
preview: {
port: 4174, // Change the default preview port
},
})
Running npm run preview again will now start the server on port 4174.
The primary benefit of preview is to catch build-specific issues before deploying. For instance, a path to an asset that works in development might break when bundled and served from a dist directory. preview exposes these problems. It’s the closest you can get to testing your deployed application without actually deploying it.
The configuration for the preview server, particularly regarding middleware, is handled by the preview.middleware option in vite.config.js, allowing you to inject custom server logic before requests are served from the dist directory.
Understanding that preview serves the dist folder is key to appreciating its role in the development workflow, bridging the gap between local development and production deployment by providing a realistic testing ground for your built application.
The next logical step after previewing your production build is to understand how to configure the underlying server used by preview for more advanced scenarios.