# What is preloadedState in Redux and How Does It Enable Server-Side Rendering?

> Understand preloadedState in Redux. Learn how this optional argument hydrates your store directly, enabling fast server-side rendering and syncing initial state between server and client.

- Repository: [Redux/redux](https://github.com/reduxjs/redux)
- Tags: deep-dive
- Published: 2026-03-05

---

**preloadedState** is the optional second argument to Redux's `createStore` function that allows you to hydrate the store with existing data, enabling seamless server-side rendering by synchronizing initial state between server and client.

In the reduxjs/redux repository, `preloadedState` serves as the foundation for isomorphic applications. It allows a Redux store to be initialized with data that exists before the application runs, rather than starting from an empty state. This capability is essential for server-side rendering (SSR) workflows where the server must capture application state and transmit it to the browser.

## Understanding preloadedState in Redux

The `preloadedState` parameter is defined in [`src/createStore.ts`](https://github.com/reduxjs/redux/blob/main/src/createStore.ts) at lines 90-96 as part of the `createStore` function signature:

```typescript
export function createStore<
  S,
  A extends Action,
  Ext extends {} = {},
  StateExt extends {} = {},
  PreloadedState = S
>(
  reducer: Reducer<S, A, PreloadedState>,
  preloadedState?: PreloadedState | undefined,
  enhancer?: StoreEnhancer<Ext, StateExt>
): Store<S, A, UnknownIfNonSpecific<StateExt>> & NoInfer<Ext>

```

When you invoke `createStore(reducer, preloadedState)`, the Redux store initializes by calling the reducer with `preloadedState` instead of `undefined`. This bypasses the reducer's default state initialization logic and uses your provided snapshot. According to [`docs/usage/Structuring-Reducers/InitializingState.md`](https://github.com/reduxjs/redux/blob/main/docs/usage/Structuring-Reducers/InitializingState.md), this establishes the precedence rules between a reducer's default state and the `preloadedState` value.

## How preloadedState Works with Server-Side Rendering

Server-side rendering with Redux relies on `preloadedState` to prevent state mismatch between server and client. The pattern ensures the client starts with the exact state the server produced, eliminating hydration errors and providing fast time-to-interactive.

### Server-Side: Creating and Serializing the Store

On the server, you fetch data needed for the specific route, create a Redux store with that data as `preloadedState`, render the React tree to a string, and serialize the final state. As documented in [`docs/usage/ServerRendering.md`](https://github.com/reduxjs/redux/blob/main/docs/usage/ServerRendering.md), you embed this serialized state in the HTML response:

```javascript
// Server-side store creation
const store = createStore(rootReducer, { data: serverFetchedData });

// After rendering to string
const preloadedState = store.getState();

// Inject into HTML
res.send(`
  <script>
    window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState).replace(/</g, '\\u003c')}
  </script>
`);

```

The `JSON.stringify` replacement of `<` characters prevents XSS attacks through state serialization.

### Client-Side: Hydrating the Store

On the client, you read the serialized state from the global variable and pass it directly to `createStore`. According to the source in [`src/createStore.ts`](https://github.com/reduxjs/redux/blob/main/src/createStore.ts) and the SSR documentation, this rehydrates the store without requiring an additional render pass:

```javascript
// Read the state injected by the server
const preloadedState = window.__PRELOADED_STATE__;

// Create store with the exact server state
const store = createStore(rootReducer, preloadedState);

```

## Code Implementation: Complete SSR Example

### Server Implementation

The following Express.js implementation demonstrates the complete server-side flow using `preloadedState`:

```javascript
// server.js
import express from 'express';
import { renderToString } from 'react-dom/server';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import rootReducer from './src/reducers';
import App from './src/App';

const app = express();

app.get('*', async (req, res) => {
  // Fetch route-specific data
  const data = await fetchDataForRoute(req.path);
  
  // Create store with preloadedState
  const store = createStore(rootReducer, { data });
  
  // Render application
  const html = renderToString(
    <Provider store={store}>
      <App />
    </Provider>
  );
  
  // Serialize state for client
  const preloadedState = store.getState();
  
  res.send(`
    <!doctype html>
    <html>
      <head><title>My App</title></head>
      <body>
        <div id="root">${html}</div>
        <script>
          window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState).replace(/</g, '\\u003c')}
        </script>
        <script src="/static/client.bundle.js"></script>
      </body>
    </html>
  `);
});

```

### Client Implementation

The client entry point reads the injected state and initializes the store:

```javascript
// client.js
import { createStore } from 'redux';
import rootReducer from './src/reducers';
import { Provider } from 'react-redux';
import { render } from 'react-dom';
import App from './src/App';

// Hydrate from server-provided state
const preloadedState = window.__PRELOADED_STATE__;

const store = createStore(rootReducer, preloadedState);

render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);

```

## Best Practices and Memory Considerations

When implementing `preloadedState` with server-side rendering, pass `window.__PRELOADED_STATE__` directly to `createStore` without assigning it to an intermediate variable when possible. As noted in [`docs/usage/ServerRendering.md`](https://github.com/reduxjs/redux/blob/main/docs/usage/ServerRendering.md) at line 180, creating an extra reference keeps the large state object alive longer than necessary, preventing the garbage collector from reclaiming memory efficiently.

Additionally, always sanitize the serialized state when embedding it in HTML to prevent XSS attacks. The replacement of `<` with its Unicode escape sequence (`\u003c`) in `JSON.stringify` output prevents script injection through malicious state properties.

## Summary

- **preloadedState** is the optional second argument to `createStore` in [`src/createStore.ts`](https://github.com/reduxjs/redux/blob/main/src/createStore.ts) that initializes the Redux store with existing data instead of starting from `undefined`.
- In server-side rendering workflows, the server creates a store with fetched data, renders the application, serializes the state to `window.__PRELOADED_STATE__`, and embeds it in the HTML response.
- The client reads the global state variable and passes it directly to `createStore`, ensuring the client starts with the exact server state and preventing hydration mismatches.
- Pass the preloaded state directly to `createStore` without intermediate variables to optimize memory usage and garbage collection.

## Frequently Asked Questions

### What happens if preloadedState conflicts with reducer default state?

When you provide `preloadedState`, Redux uses that value instead of the reducer's default state on initialization. According to [`docs/usage/Structuring-Reducers/InitializingState.md`](https://github.com/reduxjs/redux/blob/main/docs/usage/Structuring-Reducers/InitializingState.md), the `preloadedState` takes precedence during the initial dispatch, but subsequent actions will follow normal reducer logic. If you need to merge server state with defaults, handle that logic in your reducer or when preparing the `preloadedState` object.

### Can preloadedState be used for purposes other than server-side rendering?

Yes, `preloadedState` is commonly used to restore persisted state from **localStorage** or **sessionStorage**, allowing users to resume their session after refreshing the page. It can also initialize stores with configuration data loaded at build time or hydrate state from a native mobile app's embedded JavaScript environment. Any scenario where the store needs to start with existing data rather than empty initial state can utilize this parameter.

### Why does the documentation recommend passing window.__PRELOADED_STATE__ directly?

The documentation in [`docs/usage/ServerRendering.md`](https://github.com/reduxjs/redux/blob/main/docs/usage/ServerRendering.md) recommends passing the global variable directly to `createStore` to avoid creating an extra reference to the large state object. When you assign `const state = window.__PRELOADED_STATE__` and then pass `state` to `createStore`, both the global variable and your local constant reference the same data, preventing the garbage collector from reclaiming that memory until both references are cleared. Passing directly allows the global reference to be deleted or overwritten sooner, optimizing memory usage in the browser.