vitejs/vite · error · Error
The directory " " does not exist. Did you build your…
Error message
The directory "${clientOutDir}" does not exist. Did you build your project? What it means
preview() resolves the client environment's build.outDir (default 'dist') under config.root and checks for existence. If the dir is absent AND no plugin implements configurePreviewServer AND the call came from the CLI (`vite preview`), it throws, assuming the user forgot to build. The guards avoid false positives for programmatic preview use.
Solutions
- Run `vite build` first, then `vite preview`.
- If you set build.outDir, make sure the same value is used for build and that the directory exists.
- If you are wiring preview programmatically (no CLI), provide a plugin with configurePreviewServer or call the API directly — the throw only fires for the CLI entry.
- Check that the build actually succeeded and wrote files to the expected dist.
Example fix
// before $ vite preview # dist does not exist // after $ vite build && vite preview
Defensive patterns
Strategy: validation
Validate before calling
import { existsSync } from 'node:fs'
import path from 'node:path'
function assertBuilt(root, outDir) {
if (!existsSync(path.resolve(root, outDir))) {
throw new Error(`Run vite build first; ${outDir} missing`)
}
}
assertBuilt(config.root, config.environments.client.build.outDir) Type guard
function distExists(root, outDir): boolean {
return existsSync(path.resolve(root, outDir))
} Prevention
- Always run build before preview (chain them in npm scripts).
- Keep build.outDir consistent across build and preview configs.
- In CI, make the preview job depend on the build job.
When it happens
Trigger: Running `vite preview` before `vite build`, or after a build that wrote to a different outDir. The check reads config.environments.client.build.outDir, so a custom outDir pointing at a non-existent folder also triggers it.
Common situations: New users running preview directly; CI that separates build and preview stages and skipped build; renamed outDir in config but the build step ran with a different setting.
Related errors
- Environment " " is not defined in the config.
- HTTP server not available
- `input` cannot contain glob characters. They are reserved…
- Multiple entry points are not supported when output formats…
- Name in package.json is required if option…
AI-assisted analysis of vitejs/vite@b4d66fee14 (2026-08-11).
Data as JSON: /api/errors/03e2e8ea89093d4e.
Report an issue: GitHub.
Appendix: source
Thrown at packages/vite/src/node/preview.ts:153
inlineConfig,
'serve',
'production',
'production',
true,
)
const clientOutDir = config.environments.client.build.outDir
const distDir = path.resolve(config.root, clientOutDir)
if (
!fs.existsSync(distDir) &&
// error if no plugins implement `configurePreviewServer`
config.plugins.every((plugin) => !plugin.configurePreviewServer) &&
// error if called in CLI only. programmatic usage could access `httpServer`
// and affect file serving
process.argv[1]?.endsWith(path.normalize('bin/vite.js')) &&
process.argv[2] === 'preview'
) {
throw new Error(
`The directory "${clientOutDir}" does not exist. Did you build your project?`,
)
}
const httpsOptions = await resolveHttpsConfig(config.preview.https)
const app = connect() as Connect.Server
const httpServer = await resolveHttpServer(app, httpsOptions)
setClientErrorHandler(httpServer, config.logger)
const options = config.preview
const logger = config.logger
const closeHttpServer = createServerCloseFn(httpServer)
// Promise used by `server.close()` to ensure `closeServer()` is only called once
let closeServerPromise: Promise<void> | undefined
const closeServer = async () => {
teardownSIGTERMListener(closeServerAndExit)View on GitHub (pinned to b4d66fee14)