expo/expo · error · CommandError
--output-dir cannot be the same as the project directory.
Error message
--output-dir cannot be the same as the project directory.
What it means
Thrown by `exportAsync` when the resolved `--output-dir` equals the project root directory. Writing the export into the project root would clobber source files and create a recursive delete. A `CommandError` (no stack) prevents a destructive operation. The check uses `path.resolve(projectRoot, options.outputDir)` so relative paths are resolved before comparison.
Source
Thrown at packages/@expo/cli/src/export/exportAsync.ts:18
import chalk from 'chalk';
import path from 'path';
import * as Log from '../log';
import { waitUntilAtlasExportIsReadyAsync } from '../start/server/metro/debugging/attachAtlas';
import { FileNotifier } from '../utils/FileNotifier';
import { ensureDirectoryAsync, removeAsync } from '../utils/dir';
import { CommandError } from '../utils/errors';
import { ensureProcessExitsAfterDelay } from '../utils/exit';
import { exportAppAsync } from './exportApp';
import type { Options } from './resolveOptions';
export async function exportAsync(projectRoot: string, options: Options) {
// Ensure the output directory is created
const outputPath = path.resolve(projectRoot, options.outputDir);
if (outputPath === projectRoot) {
throw new CommandError('--output-dir cannot be the same as the project directory.');
} else if (projectRoot.startsWith(outputPath)) {
throw new CommandError(`--output-dir cannot be a parent directory of the project directory.`);
}
// Delete the output directory if it exists
await removeAsync(outputPath);
// Create the output directory
await ensureDirectoryAsync(outputPath);
// Export the app
await exportAppAsync(projectRoot, options);
// Stop any file watchers to prevent the CLI from hanging.
FileNotifier.stopAll();
// Wait until Atlas is ready, when enabled
// NOTE(cedric): this is a workaround, remove when `process.exit` is removed
await waitUntilAtlasExportIsReadyAsync(projectRoot);
// Final notesView on GitHub (pinned to b09195aac2)
Solutions
- Point `--output-dir` at a distinct subfolder, e.g. `--output-dir dist`.
- If scripting, validate the resolved path is not the project root before invoking the CLI.
- Avoid `.` and absolute project-root paths for `--output-dir`.
Example fix
// before expo export --output-dir . // after expo export --output-dir dist
Defensive patterns
Strategy: validation
Validate before calling
import path from 'path';
function assertSafeOutputDir(projectRoot: string, outputDir: string): void {
const out = path.resolve(projectRoot, outputDir);
if (out === path.resolve(projectRoot)) {
throw new Error('--output-dir must not equal the project root');
}
if (path.resolve(projectRoot).startsWith(out + path.sep)) {
throw new Error('--output-dir must not be an ancestor of the project root');
}
} Prevention
- Default `--output-dir` to a subfolder like `dist`.
- Validate resolved paths in CI scripts before invoking `expo export`.
- Never pass `.` or the project root absolute path as `--output-dir`.
When it happens
Trigger: Running `expo export --output-dir .` or `--output-dir <absolute project root>`. Also if `outputDir` defaults to a value that, after resolution, lands on the project root.
Common situations: CI scripts that parameterise the output dir and pass `.` or an empty string. Confusion between the project root and the desired `dist` folder. Copy-pasting a command template without filling in the path.
Related errors
- --output-dir cannot be a parent directory of the project dir
- --no-ssg can only be used with `web.output: server`
- No platforms are configured to use the Metro bundler in the
- package.json not found at ${runtimePkgPath}
- bundledNativeModules.json not found at ${BUNDLED_NATIVE_MODU
AI-assisted analysis of expo/expo@b09195aac2 (2026-08-12).
Data as JSON: /api/errors/d3f2f8f51713c3cf.
Report an issue: GitHub.