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

  1. Run `vite build` first, then `vite preview`.
  2. If you set build.outDir, make sure the same value is used for build and that the directory exists.
  3. 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.
  4. 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

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


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)