Skip to main content

What does "state normalization" do?

What state normalization is

State normalization is a way to store data in state in a "flat", structured form, in order to:

  • avoid duplicating data,
  • simplify updates,
  • reduce the number of re-renders,
  • and make the data predictable and easy to cache.

Example without normalization (bad)

javascript
const state = { posts: [ { id: 1, title: "React guide", author: { id: 10, name: "Tim" } }, { id: 2, title: "Redux patterns", author: { id: 10, name: "Tim" } // the author is duplicated } ] };

Here, the author object is duplicated in every post. If the author changes their name, you have to go through all the posts and update the copy. Also, every change to posts triggers mass re-renders.


Example with normalization

javascript
const state = { posts: [1, 2], // just IDs users: { // dictionary of entities by ID 10: { id: 10, name: "Tim" } }, entities: { posts: { 1: { id: 1, title: "React guide", authorId: 10 }, 2: { id: 2, title: "Redux patterns", authorId: 10 } } } };

Now:

  • The author is stored in one place (users[10]);
  • Posts reference the author via authorId;
  • When the author changes, you don't need to update all the posts.

Why this matters for React performance

  1. Fewer re-renders
  • When an entity is updated, React can re-render only the components that depend on that specific ID.
  • There's no "chain" reaction through nested objects.
  1. Data is easy to compare (shallow compare)
  • Objects and arrays are less nested, so === and React.memo work more efficiently.
  1. Updates are simpler
  • Changing a specific item is just an update to state.entities.posts[id].
  • No need to iterate over the whole array.
  1. Cache and selectors are optimized
  • Memoized selectors (for example, in Redux Toolkit with createSelector) work faster and more consistently.

Analogy

Imagine your state is a miniature database. Normalization turns it into tables with relationships (1:1, 1:n), instead of nested objects (like "JSON inside JSON").


This is especially useful in React / Redux

In Redux Toolkit and RTK Query, this is the recommended practice. The official normalizr library even automates the transformation:

javascript
import { normalize, schema } from 'normalizr'; const user = new schema.Entity('users'); const post = new schema.Entity('posts', { author: user }); const normalizedData = normalize(originalData, [post]);

Result:

javascript
{ entities: { users: { '10': { id: 10, name: 'Tim' } }, posts: { '1': { id: 1, title: 'React guide', author: 10 }, '2': { id: 2, title: 'Redux patterns', author: 10 } } }, result: ['1', '2'] }

Example in the context of React components

Without normalization:

javascript
function Post({ post }) { return ( <div> <h2>{post.title}</h2> <p>{post.author.name}</p> </div> ); }

If the author's name updates, React will re-render all the posts, because post.author is a new object in each one.


With normalization:

javascript
function Post({ postId }) { const post = useSelector(state => state.entities.posts[postId]); const author = useSelector(state => state.entities.users[post.authorId]); return ( <div> <h2>{post.title}</h2> <p>{author.name}</p> </div> ); }

Now updating author.name will only touch the components that depend on authorId, not the entire list of posts.


Additional benefits of normalization

BenefitDescription
Simple structureYou always know where to look for data
Easy to update and deleteYou change by ID, without complex nesting
Clear relationships between entities"One-to-many", "many-to-many"
Compatible with selectorsWorks great with memoization (useMemo, reselect)
Less JSON parsing and diffingShallow comparison is enough

When you shouldn't normalize

Excessive normalization is harmful when:

  • There isn't much data (10-20 records, a simple form);
  • Updates are rare and don't touch subtrees;
  • The data structure is static (for example, a list of tabs or a simple menu).

Normalization is needed where there is interrelated data and frequent updates.


Summary

What it doesWhy it's needed
Stores data "flat" (by ID)Eliminates duplication
Preserves relationships via IDLets you update only the entities that need it
Reduces the number of re-rendersImproves performance
Makes the logic simplerData becomes predictable
Works like a mini databaseEasy to update, search, and cache

State normalization = a database inside React state.

One source of truth for each entity: fewer re-renders, fewer bugs, higher performance.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.