# What Is the Difference Between React and React DOM? A Deep Dive into the Architecture

> Understand the core difference between React and React DOM. Learn how React defines UI elements and React DOM renders them in the browser for your web applications.

- Repository: [Meta/react](https://github.com/facebook/react)
- Tags: deep-dive
- Published: 2026-02-16

---

**React is the core library that defines what your UI should look like using elements, components, and hooks, while React DOM is the platform-specific renderer that knows how to create and update actual browser DOM nodes.**

The distinction between React and React DOM represents one of the most fundamental architectural decisions in the React ecosystem. While often used together in web applications, these two packages serve distinct purposes that enable React to work across multiple platforms. Understanding the difference between React and React DOM is essential for debugging, optimizing performance, and leveraging React's cross-platform capabilities.

## React: The Platform-Agnostic Core

React serves as the abstract engine that manages component logic, state, and the reconciliation algorithm. It operates entirely in JavaScript without any knowledge of the browser environment.

In [`packages/react/index.js`](https://github.com/facebook/react/blob/main/packages/react/index.js), the core API exports fundamental building blocks including `createElement`, `Component`, `useState`, and the `ReactVersion` constant (lines 10-74). These exports define **what** the UI should render but remain completely agnostic about **where** that rendering occurs.

### Key Responsibilities of the Core

- **Element Creation**: The `createElement` function produces plain JavaScript objects describing UI structure.
- **Component Logic**: Class components and function components manage state and lifecycle through hooks like `useState` and `useEffect`.
- **Reconciliation**: The diffing algorithm determines which parts of the tree have changed between renders.

## React DOM: The Browser-Specific Renderer

React DOM bridges the abstract React tree to the concrete browser environment. It implements the platform-specific logic required to manipulate the actual Document Object Model.

The DOM renderer lives in [`packages/react-dom/index.js`](https://github.com/facebook/react/blob/main/packages/react-dom/index.js), which re-exports the shared `ReactDOM` implementation from [`src/shared/ReactDOM.js`](https://github.com/facebook/react/blob/main/src/shared/ReactDOM.js). This architecture separates the public API from the internal implementation details.

### DOM-Specific Implementation Details

In [`packages/react-dom/src/shared/ReactDOM.js`](https://github.com/facebook/react/blob/main/packages/react-dom/src/shared/ReactDOM.js) (lines 14-68), the renderer implements browser-only functionality:

- **`createPortal`**: Allows rendering children into a DOM node outside the parent component hierarchy.
- **`flushSync`**: Forces synchronous updates for testing or integration with non-React code.
- **Container Validation**: Ensures target containers are actual DOM nodes using utilities from [`packages/react-dom-bindings/src/client/ReactDOMContainer.js`](https://github.com/facebook/react/blob/main/packages/react-dom-bindings/src/client/ReactDOMContainer.js).

## How the Separation Enables Cross-Platform Development

The decoupling of React from React DOM allows the same component code to run on entirely different platforms. This is achieved through the **reconciler pattern**, where the core React engine coordinates with platform-specific renderers via a host configuration.

The reconciler itself lives in [`packages/react-reconciler/src/ReactFiberReconciler.js`](https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberReconciler.js). It handles the diffing algorithm and component lifecycle logic, while individual renderers supply the host configuration that tells the reconciler how to create and mutate platform-specific nodes.

Alternative renderers include:

- **React Native**: Renders to native iOS/Android UI components instead of DOM elements.
- **React Three Fiber**: Renders to Three.js 3D scenes and WebGL objects.
- **React Test Renderer**: Renders to pure JavaScript objects for snapshot testing without a browser.
- **React Server**: Renders components to HTML strings on the server.

## Practical Code Examples

### Creating Elements with React Core

This example uses only the React package, with no DOM-specific code:

```javascript
import {createElement, useState} from 'react';

// Pure React element – can be rendered by any renderer
function Counter() {
  const [count, setCount] = useState(0);
  return createElement('button', {onClick: () => setCount(c => c + 1)},
    `Count: ${count}`);
}

```

### Rendering to the DOM with React DOM

This example bridges the abstract component to the browser:

```javascript
import {createRoot} from 'react-dom/client';
import {createElement} from 'react';
import {Counter} from './Counter';

const container = document.getElementById('root');
const root = createRoot(container);
root.render(createElement(Counter));

```

### Using an Alternative Renderer

This demonstrates how the same component works with React Test Renderer:

```javascript
import TestRenderer from 'react-test-renderer';
import {createElement} from 'react';
import {Counter} from './Counter';

const testInstance = TestRenderer.create(createElement(Counter));
console.log(testInstance.toJSON());

```

## Key Source Files and Their Roles

Understanding the difference between React and React DOM requires examining their source locations in the Facebook React repository:

- **[`packages/react/index.js`](https://github.com/facebook/react/blob/main/packages/react/index.js)**: Exports the core React API including `createElement`, `Component`, `useState`, and the `ReactVersion` constant (lines 10-74).

- **[`packages/react-dom/index.js`](https://github.com/facebook/react/blob/main/packages/react-dom/index.js)**: Public entry point for the DOM renderer that re-exports `ReactDOM` symbols from the shared implementation.

- **[`packages/react-dom/src/shared/ReactDOM.js`](https://github.com/facebook/react/blob/main/packages/react-dom/src/shared/ReactDOM.js)**: Implements DOM-specific methods such as `createPortal`, `flushSync`, and `unstable_batchedUpdates`, plus validation to ensure target containers are actual DOM nodes (lines 14-68).

- **[`packages/react-reconciler/src/ReactFiberReconciler.js`](https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberReconciler.js)**: The reconciler core that coordinates work between React and any host configuration, enabling the same components to work across different platforms.

- **[`packages/react-dom-bindings/src/client/ReactDOMContainer.js`](https://github.com/facebook/react/blob/main/packages/react-dom-bindings/src/client/ReactDOMContainer.js)**: Utility functions that verify whether a target is a valid DOM container for React rendering.

## Summary

- **React** is the platform-agnostic core that defines UI structure and behavior through elements, components, and hooks, independent of any rendering environment.
- **React DOM** is the browser-specific renderer that creates and manages actual DOM nodes, handling platform-specific concerns like events and portals.
- The architectural separation allows React to work across multiple platforms (Native, Three.js, Server) using different renderers while sharing the same component code.
- The reconciler (`ReactFiberReconciler`) bridges the core and platform-specific implementations, coordinating updates through host configurations.

## Frequently Asked Questions

### Can you use React without React DOM?

Yes. React can be used with alternative renderers such as React Native for mobile apps, React Three Fiber for 3D scenes, or React Test Renderer for unit testing. These packages replace React DOM while using the same React core API, allowing components to remain completely portable across platforms.

### Why are React and React DOM separate packages?

The separation follows the renderer pattern, allowing the same component logic to run on different platforms. By keeping the core platform-agnostic, Meta can maintain one reconciliation engine while community and internal teams build specialized renderers for web, mobile, and other environments. This modularity reduces bundle sizes for non-DOM targets and enforces clean architectural boundaries.

### What happens if I import `createElement` from `react-dom` instead of `react`?

You should not import `createElement` from `react-dom` because it is not exported there. Attempting to do so will result in an import error or `undefined`. Always import `createElement`, `Component`, and hooks from the `react` package, and import renderer-specific methods like `createRoot` or `createPortal` from `react-dom`.

### Is the reconciler the same in React and React DOM?

The reconciler is shared between them. React DOM consumes the reconciler from `react-reconciler` to apply updates to the browser DOM. The reconciler handles the diffing algorithm and component lifecycle logic, while React DOM provides the host configuration that tells the reconciler how to create and mutate actual DOM nodes. This shared reconciler is what makes cross-platform rendering possible.