remix-run/react-router · error

The "@mdx-js/rollup" plugin should be placed before the…

Error message

The "@mdx-js/rollup" plugin should be placed before the React Router plugin in your Vite config

What it means

React Router's Vite plugin registers a config hook that validates plugin ordering. The '@mdx-js/rollup' plugin must appear BEFORE the React Router plugin in the Vite 'plugins' array so that MDX route modules are compiled to plain JS before React Router applies its own route-module transforms. The check compares the index of '@mdx-js/rollup' against the index of the react-router plugin and throws when MDX comes later, because the React Router transforms would otherwise run on uncompiled .mdx files.

Solutions

  1. Move mdx() above reactRouter() in the vite.config.ts plugins array
  2. Re-run 'react-router dev' or 'react-router build' to confirm the config hook passes
  3. Check for duplicated plugin registrations (e.g. mdx() added twice in different spots) if the error persists

Example fix

// before (vite.config.ts)
import { reactRouter } from "@react-router/dev/vite";
import mdx from "@mdx-js/rollup";
export default defineConfig({
  plugins: [reactRouter(), mdx()],
});

// after
export default defineConfig({
  plugins: [mdx(), reactRouter()],
});
Defensive patterns

Strategy: validation

Validate before calling

// run before vite boots (e.g. in a prebuild script)
import { resolveConfig } from "vite";
const cfg = await resolveConfig({ configFile: "vite.config.ts" }, "serve");
const names = cfg.plugins.map((p) => p.name);
const mdx = names.indexOf("@mdx-js/rollup");
const rr = names.findIndex((n) => n.startsWith("react-router"));
if (mdx !== -1 && rr !== -1 && mdx > rr) {
  throw new Error("Move @mdx-js/rollup before the React Router plugin");
}

Prevention

When it happens

Trigger: A vite.config.ts whose plugins array is ordered as [reactRouter(), mdx()], i.e. mdxPluginIndex >= 0 and mdxPluginIndex > reactRouterPluginIndex (where the React Router index matches plugin names 'react-router' or 'react-router/rsc').

Common situations: Adding MDX support to a Framework Mode app by appending mdx() at the end of the plugins array; copying a Vite config from an MDX tutorial that places mdx() last; converting a plain Vite+MDX site to React Router and keeping the old plugin order.

Related errors


AI-assisted analysis of remix-run/react-router@6beaca3952 (2026-08-18). Data as JSON: /api/errors/33b46107e0ec2003. Report an issue: GitHub.

Appendix: source

Thrown at packages/react-router-dev/vite/plugins/validate-plugin-order.ts:32

      let reactRouterRscPluginIndex = pluginIndex("react-router/rsc");
      let viteRscPluginIndex = pluginIndex("rsc");
      if (
        reactRouterRscPluginIndex >= 0 &&
        viteRscPluginIndex >= 0 &&
        reactRouterRscPluginIndex > viteRscPluginIndex
      ) {
        throw new Error(
          `The "@vitejs/plugin-rsc" plugin should be placed after the React Router RSC plugin in your Vite config`,
        );
      }

      let reactRouterPluginIndex = pluginIndex([
        "react-router",
        "react-router/rsc",
      ]);
      let mdxPluginIndex = pluginIndex("@mdx-js/rollup");
      if (mdxPluginIndex >= 0 && mdxPluginIndex > reactRouterPluginIndex) {
        throw new Error(
          `The "@mdx-js/rollup" plugin should be placed before the React Router plugin in your Vite config`,
        );
      }
    },
  };
}

View on GitHub (pinned to 6beaca3952)