remix-run/react-router · critical · Error

The React Router Vite plugin requires the use of a Vite conf

Error message

The React Router Vite plugin requires the use of a Vite config file

What it means

Thrown in the `configResolved` hook when the React Router plugin bootstraps its child compiler. To give the child compiler independent plugin state, React Router reloads the user's config via `vite.loadConfigFromFile` using `viteConfig.configFile`. If `configFile` is falsy — meaning Vite was driven purely by inline options or auto-discovery without recording a file — React Router cannot create an isolated plugin set and aborts.

Source

Thrown at packages/react-router-dev/vite/plugin.ts:1429

          };
        }
      },
      async configResolved(resolvedViteConfig) {
        await initEsModuleLexer;

        viteConfig = resolvedViteConfig;
        invariant(viteConfig);

        // We load the same Vite config file again for the child compiler so
        // that both parent and child compiler's plugins have independent state.
        // If we re-used the `viteUserConfig.plugins` array for the child
        // compiler, it could lead to mutating shared state between plugin
        // instances in unexpected ways, e.g. during `vite build` the
        // `configResolved` plugin hook would be called with `command = "build"`
        // by parent and then `command = "serve"` by child, which some plugins
        // may respond to by updating state referenced by the parent.
        if (!viteConfig.configFile) {
          throw new Error(
            "The React Router Vite plugin requires the use of a Vite config file",
          );
        }

        let vite = getVite();

        let childCompilerConfigFile = await vite.loadConfigFromFile(
          {
            command: viteConfig.command,
            mode: viteConfig.mode,
          },
          viteConfig.configFile,
        );

        invariant(
          childCompilerConfigFile,
          "Vite config file was unable to be resolved for React Router child compiler",
        );

View on GitHub (pinned to 1fd704a7da)

Solutions

  1. Create a `vite.config.ts` at the project root that registers `reactRouter()`.
  2. If using `--config`, ensure the path resolves to an existing file.
  3. Avoid `configFile: false` when programmatically building with the React Router plugin.
  4. Run from the package directory that owns the `vite.config.ts`.

Example fix

// before: programmatic build with no config file
await createServer({ configFile: false, plugins: [reactRouter()] });
// after: ship a real vite.config.ts and let Vite load it
// vite.config.ts
import { reactRouter } from "@react-router/dev";
export default defineConfig({ plugins: [reactRouter()] });
Defensive patterns

Strategy: validation

Validate before calling

import { existsSync } from "node:fs";
const ensureConfigFile = (p = "./vite.config.ts") => {
  if (!existsSync(p)) throw new Error(`Missing Vite config file: ${p}`);
};

Prevention

When it happens

Trigger: Running the React Router plugin against a Vite invocation that has no `vite.config.{ts,js,mjs}` on disk (e.g. `vite build` with `--config` pointing at nothing, or a programmatic `createServer({ configFile: false })`); a config file that failed to load and silently left `configFile` undefined; a monorepo where the wrong package's directory is the CWD.

Common situations: Programmatically invoking Vite from a script with `configFile: false`; running tools that wrap Vite (Storybook, custom SSR harnesses) without a real config file; an empty `.vite/config` after a botched setup.

Related errors


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