{"record":{"id":"03e2e8ea89093d4e","repo":"vitejs/vite","slug":"the-directory-clientoutdir-does-not-exist-di","errorCode":null,"errorMessage":"The directory \"${clientOutDir}\" does not exist. Did you build your project?","messagePattern":"The directory \"(.+?)\" does not exist\\. Did you build your project\\?","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/vite/src/node/preview.ts","lineNumber":153,"sourceCode":"    inlineConfig,\n    'serve',\n    'production',\n    'production',\n    true,\n  )\n\n  const clientOutDir = config.environments.client.build.outDir\n  const distDir = path.resolve(config.root, clientOutDir)\n  if (\n    !fs.existsSync(distDir) &&\n    // error if no plugins implement `configurePreviewServer`\n    config.plugins.every((plugin) => !plugin.configurePreviewServer) &&\n    // error if called in CLI only. programmatic usage could access `httpServer`\n    // and affect file serving\n    process.argv[1]?.endsWith(path.normalize('bin/vite.js')) &&\n    process.argv[2] === 'preview'\n  ) {\n    throw new Error(\n      `The directory \"${clientOutDir}\" does not exist. Did you build your project?`,\n    )\n  }\n\n  const httpsOptions = await resolveHttpsConfig(config.preview.https)\n  const app = connect() as Connect.Server\n  const httpServer = await resolveHttpServer(app, httpsOptions)\n  setClientErrorHandler(httpServer, config.logger)\n\n  const options = config.preview\n  const logger = config.logger\n\n  const closeHttpServer = createServerCloseFn(httpServer)\n\n  // Promise used by `server.close()` to ensure `closeServer()` is only called once\n  let closeServerPromise: Promise<void> | undefined\n  const closeServer = async () => {\n    teardownSIGTERMListener(closeServerAndExit)","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/vitejs/vite/blob/b4d66fee14d970f45b8a6f3d7d6aee73ca9b88ab/packages/vite/src/node/preview.ts#L135-L171","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n$ vite preview   # dist does not exist\n// after\n$ vite build && vite preview","handlingStrategy":"validation","validationCode":"import { existsSync } from 'node:fs'\nimport path from 'node:path'\nfunction assertBuilt(root, outDir) {\n  if (!existsSync(path.resolve(root, outDir))) {\n    throw new Error(`Run vite build first; ${outDir} missing`)\n  }\n}\nassertBuilt(config.root, config.environments.client.build.outDir)","typeGuard":"function distExists(root, outDir): boolean {\n  return existsSync(path.resolve(root, outDir))\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["preview","build","cli","config"],"backgroundTag":null,"analyzedSha":"b4d66fee14d970f45b8a6f3d7d6aee73ca9b88ab","analyzedAt":"2026-08-11T11:49:19.515Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}