The ReactDOM.render method is deprecated in React 18 and will no longer be supported.

This means your React application is trying to use an old API to mount your root component, and React 18 is telling you it doesn’t know how to handle that request anymore. The system level failure is that the React DOM renderer, which is responsible for taking your React components and turning them into actual DOM elements that the browser can display, has been updated to expect a new way of being initialized. It’s essentially a version mismatch at the core of how React talks to your webpage.

Here are the common causes and their fixes:

1. Outdated react-dom Version

  • Diagnosis: Check your package.json file. You should have react and react-dom listed as dependencies, and ideally, both should be at version 18.x. If react-dom is still on a version below 18, this is your problem.
  • Fix:
    npm install react-dom@latest
    # or
    yarn add react-dom@latest
    
    This command will update react-dom to the latest compatible version with your react package, which should be 18.x if your react is also up-to-date.
  • Why it works: React 18 introduced the new concurrent rendering features, and the createRoot API is integral to enabling them. Older versions of react-dom simply don’t contain the necessary logic to work with React 18’s rendering engine.

2. Incorrect Root Mounting Code

  • Diagnosis: Examine your index.js (or equivalent entry file). Look for any code that uses ReactDOM.render. It will likely look something like this:
    import ReactDOM from 'react-dom';
    import App from './App';
    
    ReactDOM.render(<App />, document.getElementById('root'));
    
  • Fix: Replace ReactDOM.render with the new createRoot API.
    import ReactDOM from 'react-dom/client'; // Note the '/client'
    import App from './App';
    
    const container = document.getElementById('root');
    const root = ReactDOM.createRoot(container); // Create a root
    root.render(<App />); // Render your app
    
    This change is fundamental. You now first get a reference to the DOM element you want to mount to, then you create a "root" instance from that element using ReactDOM.createRoot(), and finally, you call render() on that root instance.
  • Why it works: createRoot is React 18’s new entry point for the DOM. It sets up the environment for concurrent rendering and tells React where in the DOM your application lives. ReactDOM.render was the old way and is no longer part of the public API for React 18.

3. Multiple React Installations (Less Common)

  • Diagnosis: If you’re working on a large project or have integrated React into an existing non-React application, you might accidentally have multiple versions of React or react-dom installed, or they might be resolved incorrectly. Run npm ls react-dom or yarn list react-dom in your project’s root directory. If you see multiple versions listed or unexpected entries, this could be the culprit.
  • Fix: Clean your node_modules and reinstall:
    rm -rf node_modules
    npm install
    # or
    rm -rf node_modules
    yarn install
    
    If the problem persists, you might need to use npm dedupe or yarn dedupe to try and resolve conflicting package versions, or manually adjust your package.json to enforce a single version.
  • Why it works: When multiple versions of a core library like react-dom are present, the JavaScript runtime can get confused about which implementation to use, leading to unexpected errors like using an old API from one version while expecting behavior from another.

4. Incorrect Import Path for react-dom

  • Diagnosis: Double-check the import statement for react-dom. As shown in fix #2, for React 18, you must import from 'react-dom/client'. If you’re still importing from 'react-dom', even if you’re using createRoot, the system won’t find the correct functions.
  • Fix: Ensure your import statement is:
    import ReactDOM from 'react-dom/client';
    
    Change any instances of import ReactDOM from 'react-dom'; to this new path when using createRoot.
  • Why it works: The react-dom/client entry point specifically exposes the new APIs required for React 18’s root mounting and concurrent features. The older react-dom package is essentially frozen in time and doesn’t contain these new functions.

5. Using a Package That Hasn’t Updated to React 18

  • Diagnosis: This is more of an indirect cause. If a third-party component or library you’re using internally relies on ReactDOM.render and hasn’t been updated to use createRoot, your entire application might fail. You’ll usually see the error originating from the third-party library’s code in your browser’s developer console.
  • Fix: Update the problematic third-party package to its latest version. If no update is available, you might need to fork the package, update it yourself, or find an alternative.
    npm update <package-name>
    # or
    yarn upgrade <package-name>
    
    If the package is older and unmaintained, you might have to look for a replacement.
  • Why it works: By updating the third-party package, you ensure it’s using the correct React 18 APIs, thus resolving the conflict and allowing your application to mount correctly.

6. Using ReactDOM.hydrate Instead of createRoot (Server-Side Rendering)

  • Diagnosis: If you’re using server-side rendering (SSR) and see this error, you might be using ReactDOM.hydrate incorrectly. Similar to render, hydrate has also been updated.
  • Fix: For SSR with React 18, you should use hydrateRoot from 'react-dom/client'.
    import ReactDOM from 'react-dom/client';
    import App from './App';
    
    const container = document.getElementById('root');
    const root = ReactDOM.hydrateRoot(container, <App />); // Use hydrateRoot
    
    If you are not using SSR, ensure you are using createRoot and not hydrateRoot.
  • Why it works: hydrateRoot is the SSR counterpart to createRoot. It initializes React on the client-side by attaching to pre-rendered HTML from the server, preserving the server’s output while enabling client-side interactivity.

After fixing this, the next error you’ll likely encounter is related to the new Suspense features or other concurrent rendering behaviors if your application isn’t fully prepared for React 18’s more advanced capabilities.

Want structured learning?

Take the full React course →