# React 19 Compiler: Why I Deleted All My useMemo Calls
By Govind Bajaj · 2026

Tags: react, react-19, performance, compiler, hooks
The React Compiler made manual memoization obsolete. I removed 47 useMemo and useCallback hooks from a production app. The bundle got smaller. The code got cleaner. Here's what happened.
I deleted 47 `useMemo` and `useCallback` calls from a production React app last month.

The app got faster. The bundle got smaller. And the code became readable again.

This is the React 19 Compiler (formerly React Forget), and it changes everything about how we write performant React.

## The Memoization Tax We've All Paid

For years, optimizing React meant wrapping values in `useMemo`, functions in `useCallback`, and components in `React.memo`. The pattern was so repetitive that ESLint plugins existed to enforce it.

But manual memoization has real costs:

- **Cognitive overhead**: Every developer on the team needs to understand dependency arrays, stale closure traps, and the difference between referential and deep equality
- **Bundle size**: `useMemo` and `useCallback` are runtime hooks — they ship JS to the client
- **Bugs**: Wrong dependency arrays cause silent failures. Missing dependencies cause stale data. Empty dependency arrays cause missed updates
- **Readability**: A component with six `useMemo` calls is harder to follow than one that just computes values

Here's the before picture from a real component in the Royal Madrasi admin dashboard:

```tsx
// Before: manual memoization everywhere
function SalesChart({ orders, dateRange, filter }) {
  const filteredOrders = useMemo(
    () => orders.filter(o => o.status === filter),
    [orders, filter]
  )
  
  const dailyTotals = useMemo(
    () => calculateDailyTotals(filteredOrders, dateRange),
    [filteredOrders, dateRange]
  )
  
  const chartData = useMemo(
    () => formatForRecharts(dailyTotals),
    [dailyTotals]
  )
  
  const handleBarClick = useCallback(
    (data) => router.push(`/orders/${data.id}`),
    [router]
  )
  
  return <BarChart data={chartData} onClick={handleBarClick} />
}
```

Four memoization hooks for a simple data pipeline. And I got the `filteredOrders` dependency wrong twice during development.

## The Compiler Does It Automatically

The React Compiler analyzes your component's data flow and applies memoization only where it's beneficial. You write plain JavaScript. The compiler ensures values and functions retain their identity across renders when nothing changed.

```tsx
// After: just write the computation
function SalesChart({ orders, dateRange, filter }) {
  const filteredOrders = orders.filter(o => o.status === filter)
  const dailyTotals = calculateDailyTotals(filteredOrders, dateRange)
  const chartData = formatForRecharts(dailyTotals)
  
  const handleBarClick = (data) => router.push(`/orders/${data.id}`)
  
  return <BarChart data={chartData} onClick={handleBarClick} />
}
```

No hooks. No dependency arrays. No stale closure worries. The compiler generates the equivalent of `useMemo` and `useCallback` at build time, not runtime.

## How to Enable It

Install the Babel plugin:

```bash
npm install -D babel-plugin-react-compiler
```

Add to your Babel config:

```js
// babel.config.js
module.exports = {
  plugins: [
    ['babel-plugin-react-compiler', {}]
  ]
}
```

For Next.js, add to `next.config.ts`:

```ts
// next.config.ts
const nextConfig = {
  experimental: {
    reactCompiler: true
  }
}

export default nextConfig
```

The compiler runs at build time. It does not ship any runtime code. Your bundle gets smaller because `useMemo` and `useCallback` imports can be removed.

## What Gets Compiled

The compiler memoizes:

- Expensive computations inside components
- Object and array literals passed as props
- Event handler functions
- JSX creation to avoid unnecessary re-renders

It does NOT memoize:

- Side effects (still need `useEffect`)
- External mutable data (still need state management)
- Values that genuinely change every render

## The One Thing You Still Need to Know

The compiler respects React's rules of hooks and the data flow model. But it cannot fix architectural performance problems. If you compute a factorial inside a component that re-renders 60 times per second, the compiler will memoize the computation but you'll still have 60 memoization checks per second.

Move that computation out of the render path entirely — use `useDeferredValue`, `useTransition`, or move it to a Server Component.

## Results from Production

After removing manual memoization from the Sans Herbals checkout flow:

- Bundle size: -4.2KB gzipped (removed useMemo/useCallback imports and dependency array code)
- Component readability: significantly improved (new devs don't need to trace dependency arrays)
- Runtime performance: equivalent or slightly better (compiler-generated memo is more precise than manual)
- Bug rate: fewer stale-data bugs in the first two weeks than the previous two months

## Takeaways

- The React 19 Compiler makes manual `useMemo` and `useCallback` obsolete
- Enable it with one config flag in Next.js — no code changes required
- Delete your memoization hooks after enabling it (keeping them is harmless but unnecessary)
- The compiler runs at build time, so your bundle gets smaller, not larger
- You still need `useEffect` for side effects and proper architecture for expensive computations
- This is the biggest change to React performance since hooks were introduced