remix-run/react-router · error · Error

Could not find a root route module in the app directory: ${a

Error message

Could not find a root route module in the app directory: ${appDirectory}

What it means

Thrown by flatRoutes() (createFileRouteMapper) when findFile(appDirectory, 'root', routeModuleExts) returns null — i.e. no root route module (root.tsx/root.jsx/root.ts/…) exists directly in the app directory. The root route is mandatory for file-system routing because it provides the <html> shell and layout.

Source

Thrown at packages/react-router-fs-routes/flatRoutes.ts:87

    return values;
  }
}

export function flatRoutes(
  appDirectory: string,
  ignoredFilePatterns: string[] = [],
  prefix = "routes",
) {
  let ignoredFileRegex = Array.from(new Set(["**/.*", ...ignoredFilePatterns]))
    .map((re) => makeRe(re))
    .filter((re: any): re is RegExp => !!re);
  let routesDir = path.join(appDirectory, prefix);

  let rootRoute = findFile(appDirectory, "root", routeModuleExts);

  if (!rootRoute) {
    throw new Error(
      `Could not find a root route module in the app directory: ${appDirectory}`,
    );
  }

  if (!fs.existsSync(routesDir)) {
    throw new Error(
      `Could not find the routes directory: ${routesDir}. Did you forget to create it?`,
    );
  }

  // Only read the routes directory
  let entries = fs.readdirSync(routesDir, {
    withFileTypes: true,
    encoding: "utf-8",
  });

  let routes: string[] = [];
  for (let entry of entries) {

View on GitHub (pinned to 1fd704a7da)

Solutions

  1. Create app/root.tsx (default export a component rendering <html>… with <Outlet/>).
  2. Verify react-router.config.ts `appDirectory` points to the folder that should contain root.tsx.
  3. Run `pnpm react-router typegen` to confirm the route manifest resolves.
  4. Check that the file extension is in the supported routeModuleExts list (ts,tsx,js,jsx,mdx).

Example fix

// before: app/ has only routes/, no root file → create app/root.tsx
// app/root.tsx
import { Outlet } from 'react-router';
export default function Root() {
  return (<html><body><Outlet/></body></html>);
}
Defensive patterns

Strategy: validation

Validate before calling

import { existsSync } from 'node:fs';
import { exts } from './routeModuleExts'; // mimic the supported list: ts,tsx,js,jsx,mdx,...
function hasRootRoute(appDirectory: string): boolean {
  return ['ts','tsx','js','jsx','mdx'].some((e) => existsSync(`${appDirectory}/root.${e}`));
}
if (!hasRootRoute(appDirectory)) throw new Error('Missing app/root.tsx');

Type guard

function appDirectoryHasRoot(appDirectory: string, exts: string[]): boolean {
  const { existsSync } = require('node:fs');
  return exts.some((e) => existsSync(`${appDirectory}/root.${e}`));
}

Prevention

When it happens

Trigger: Calling flatRoutes() (directly or via the fs-routes default export) where the app directory has no file matching `root.{ts,tsx,js,jsx,...}`. Common when appDirectory is misconfigured (points to the wrong folder) or the root file was renamed/deleted.

Common situations: Setting `appDirectory` in react-router.config.ts to a custom path that doesn't contain root.tsx. Fresh scaffold where root.tsx wasn't generated. Renaming root.tsx to app.tsx (not a supported convention). Monorepo where the app dir resolves to the package root instead of ./app.

Related errors


AI-assisted analysis of remix-run/react-router@1fd704a7da (2026-08-12). Data as JSON: /api/errors/c92164f789294d7a. Report an issue: GitHub.