The react/jsx-runtime module failed to load because the React Fragment shorthand <> was used without the necessary Babel plugin.
The core issue is that the <> syntax for React Fragments is not standard JSX. It’s a syntactic sugar that Babel needs to transform into React.Fragment calls before React can understand it. When this transformation doesn’t happen, the react/jsx-runtime module, which expects standard JSX output, can’t find the Fragment component it needs.
Here are the common reasons this happens and how to fix them:
1. Missing @babel/plugin-transform-react-jsx in Babel Configuration
This is the most frequent culprit. Your Babel configuration (usually in babel.config.js or .babelrc) needs to explicitly tell Babel to handle React JSX, including the fragment shorthand.
Diagnosis:
Check your babel.config.js or .babelrc file. Look for a plugins array.
Fix:
Add "@babel/plugin-transform-react-jsx" to your plugins array. If you’re using presets like @babel/preset-react, this plugin is often included automatically, but sometimes explicit configuration is needed, especially in newer setups or when customizing presets.
Example babel.config.js:
module.exports = {
presets: [
'next/babel', // or '@babel/preset-env', '@babel/preset-react'
],
plugins: [
// Ensure this is present if not implicitly handled by presets
['@babel/plugin-transform-react-jsx', { runtime: 'automatic' }],
],
};
Why it works: This explicitly instructs Babel to process JSX syntax, including the shorthand fragment, and transform it into valid JavaScript that React can interpret. The runtime: 'automatic' option is crucial for modern React versions which use the new JSX transform.
2. Incorrect runtime Option in Babel Plugin
Even if the plugin is present, it might be configured incorrectly, especially regarding the JSX runtime. React 17+ introduced a new JSX transform that doesn’t require import React from 'react' in every file. This new transform relies on specific Babel configurations.
Diagnosis:
Examine the configuration for @babel/plugin-transform-react-jsx. Ensure the runtime option is set to 'automatic'.
Fix:
Modify the plugin configuration in your babel.config.js or .babelrc to include runtime: 'automatic'.
Example babel.config.js:
module.exports = {
presets: [
'next/babel',
],
plugins: [
['@babel/plugin-transform-react-jsx', { runtime: 'automatic' }],
],
};
Why it works: Setting runtime: 'automatic' tells Babel to use the new JSX transform. This means Babel will automatically import the necessary functions from react/jsx-runtime (or react/jsx-dev-runtime for development) behind the scenes, allowing the <> shorthand to be correctly processed.
3. react/jsx-runtime Not Installed or Incorrectly Linked
The automatic JSX transform relies on the react/jsx-runtime and react/jsx-dev-runtime modules being available. If these are missing or corrupted in your node_modules, the build will fail.
Diagnosis:
Check your node_modules/react directory. Ensure jsx-runtime.js and jsx-dev-runtime.js exist. Also, run npm list react or yarn list react to verify the installed version.
Fix: Reinstall React and its related packages:
# If using npm
npm install react react-dom
# If using yarn
yarn add react react-dom
If the issue persists, try deleting your node_modules folder and package-lock.json (or yarn.lock) and running npm install (or yarn install) again.
Why it works: This ensures that the necessary runtime modules are present and correctly linked within your project’s dependencies, allowing Babel and React to find them.
4. Incorrect Babel Preset Configuration (e.g., preset-react vs. preset-react-transform)
Older configurations might use @babel/preset-react with specific options that don’t align with the new JSX transform. Newer versions of @babel/preset-react often handle the runtime: 'automatic' configuration for you, but conflicts can arise.
Diagnosis:
Review the configuration of @babel/preset-react or any other React-specific Babel presets. Look for options related to runtime or useSpread.
Fix:
Ensure your @babel/preset-react is up-to-date and correctly configured. If you’re manually configuring the JSX plugin, make sure it’s compatible with your preset. Often, simply updating the preset and ensuring it’s applied correctly is enough.
Example babel.config.js (using Next.js which handles this):
// next.config.js
module.exports = {
// ... other Next.js config
};
// babel.config.js (if you need custom overrides beyond next/babel)
module.exports = {
presets: ['next/babel'], // next/babel configures the react preset correctly
};
Why it works: Modern React presets are designed to work seamlessly with the new JSX transform. By ensuring the correct preset is used and updated, you leverage its built-in configurations for the JSX runtime.
5. Using a Bundler/Transpiler That Doesn’t Support the New JSX Transform
Some older or less common build tools might not have updated their integrations to properly support the new JSX transform introduced in React 17.
Diagnosis:
Check the documentation for your specific bundler (e.g., Webpack, Rollup, Parcel, Vite) and its Babel integration. Verify that it’s configured to use Babel correctly and supports the runtime: 'automatic' option.
Fix:
Update your bundler and its associated Babel plugins/loaders to their latest versions. For example, if using Webpack, ensure you have @babel/loader installed and configured correctly.
Example Webpack configuration snippet:
// webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /\.(js|jsx|ts|tsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['next/babel'], // or your custom Babel config
plugins: [
['@babel/plugin-transform-react-jsx', { runtime: 'automatic' }],
],
},
},
},
],
},
// ...
};
Why it works: This ensures that your build tool is correctly passing your code through Babel with the appropriate configuration, enabling the transformation of JSX syntax.
6. Project Structure or Monorepo Configuration Issues
In monorepos (using Yarn Workspaces, Lerna, pnpm workspaces), dependency hoisting or incorrect Babel configurations across packages can lead to the react/jsx-runtime module not being found or being the wrong version.
Diagnosis:
In a monorepo, check if react is hoisted to the root node_modules or if each package has its own version. Verify that the Babel configuration in the root or the specific package is correctly pointing to the installed Babel plugins.
Fix:
Ensure that @babel/plugin-transform-react-jsx is installed as a devDependency in the package that is building the React code. If using workspaces, ensure the Babel configuration is correctly applied and that dependencies are resolvable. Sometimes, explicitly installing the Babel plugin in the affected package (even if it’s in the root node_modules) can resolve hoisting issues.
Why it works: This ensures that the Babel plugin is available in the context where the code is being transpiled and that it can correctly resolve the react/jsx-runtime dependency, regardless of how dependencies are managed in the monorepo.
After applying these fixes, you might encounter a TypeError: Object(...) is not a function if you’ve used React.useState or React.useEffect without import React from 'react' and the Babel configuration is still not set to runtime: 'automatic'.