withastro/astro · error · Error

[preview] The output directory

Error message

[preview] The output directory ${outDirPath} does not exist. Did you run `astro build`?

What it means

`astro preview` serves the artifacts produced by `astro build`. For a static build (no adapter preview entrypoint), it starts a static file server rooted at the client output directory (`dist/client` by default) and first verifies it exists with `fs.existsSync`. If the directory is absent there is nothing to serve, so preview aborts and suggests running the build first.

Solutions

  1. Run `astro build` before `astro preview` (e.g. chain them: `astro build && astro preview`)
  2. Verify `outDir` and `build.client` in astro.config match the directory preview expects
  3. Run preview from the project root (where astro.config lives) so the relative outDir resolves correctly
  4. If the build itself fails, fix the build errors first — preview cannot run without its output

Example fix

# before
astro preview
# after
astro build && astro preview
Defensive patterns

Strategy: validation

Validate before calling

// scripts/preview.mjs — gate preview on the build output existing
import { existsSync } from 'node:fs';
import { resolve } from 'node:path';
const clientOutDir = resolve('dist/client'); // must match build.client / outDir
if (!existsSync(clientOutDir)) {
  console.error(`Missing ${clientOutDir} — run \`astro build\` first`);
  process.exit(1);
}
// then spawn `astro preview`

Prevention

When it happens

Trigger: Running `astro preview` on a static site before `astro build` has ever emitted output; a build that failed partway before writing the client bundle; a custom `outDir`/`build.client` config that differs from where the build actually wrote; running preview from the wrong working directory so the relative outDir resolves elsewhere.

Common situations: Fresh clone where only `astro dev` was run; CI pipelines that separate build and preview stages and skip the build step; `dist/` removed by a clean task or `.gitignore` workflow; outDir changed in astro.config after the last build.

Related errors


AI-assisted analysis of withastro/astro@52e6c34790 (2026-08-18). Data as JSON: /api/errors/5f2addb23c15d07c. Report an issue: GitHub.

Appendix: source

Thrown at packages/astro/src/core/preview/index.ts:54

	const settings = await runHookConfigSetup({
		settings: _settings,
		command: 'preview',
		logger: logger,
	});

	// Create a route manifest and determine buildOutput from actual routes.
	// Route scanning sets settings.buildOutput to 'server' if any route is non-prerendered.
	settings.buildOutput = getPrerenderDefault(settings.config) ? 'static' : 'server';
	await createRoutesList({ settings: settings, cwd: inlineConfig.root }, logger);

	await runHookConfigDone({ settings: settings, logger: logger, command: 'preview' });

	if (settings.buildOutput === 'static' && !settings.adapter?.previewEntrypoint) {
		const clientOutDir = getClientOutputDirectory(settings);
		if (!fs.existsSync(clientOutDir)) {
			const outDirPath = fileURLToPath(clientOutDir);
			throw new Error(
				`[preview] The output directory ${outDirPath} does not exist. Did you run \`astro build\`?`,
			);
		}
		const server = await createStaticPreviewServer(settings, logger);
		return server;
	}

	if (!settings.adapter) {
		throw new Error(`[preview] No adapter found.`);
	}

	if (!settings.adapter.previewEntrypoint) {
		throw new Error(
			`[preview] The ${settings.adapter.name} adapter does not support the preview command.`,
		);
	}
	// We need to use require.resolve() here so that advanced package managers like pnpm
	// don't treat this as a dependency of Astro itself. This correctly resolves the

View on GitHub (pinned to 52e6c34790)