Back to blog
October 2026

React Compiler Explained: Do We Still Need useMemo and useCallback?

React Compiler is an official build-time optimization tool that automatically memoizes React components, values, and functions. Learn how it works, whether useMemo and useCallback are still necessary, how to configure it with Vite and Next.

  • React
  • React compiler
  • Performance
  • JavaScript
  • TypeScript
  • Optimization
React Compiler Explained: Do We Still Need useMemo and useCallback?

React Compiler Explained: Do We Still Need useMemo and useCallback?

Introduction

One of the recurring challenges in React development is managing unnecessary re-renders and avoiding expensive calculations during component updates.

For years, developers have relied on tools such as useMemo, useCallback, and React.memo to control rendering behavior and improve performance.

Although these tools are useful, manual memoization introduces additional complexity. Developers must understand dependency arrays, preserve stable references, and decide which components or calculations actually need optimization.

React Compiler introduces a different approach: instead of requiring developers to manually identify every optimization opportunity, it analyzes React code at build time and automatically applies memoization where it can.

React Compiler reached its stable 1.0 release in October 2025. It is now suitable for production adoption, provided that applications follow React's rules and are properly tested.

In this article, we'll explore what React Compiler is, how automatic memoization works, whether traditional memoization Hooks are still necessary, and how to enable it in modern React applications.

What Is React Compiler?

React Compiler is a build-time optimization tool that analyzes React components and Hooks and automatically applies memoization to code that can be safely optimized.

In simple terms, it attempts to avoid unnecessary recalculations and re-renders without requiring developers to manually wrap every component, function, or computed value in memoization APIs.

Consider the following example:

import { useMemo, useCallback, memo } from "react";

const ProductList = memo(function ProductList({
  products,
  onSelect,
}: {
  products: Product[];
  onSelect: (id: string) => void;
}) {
  const sortedProducts = useMemo(
    () => products.toSorted((a, b) => a.price - b.price),
    [products]
  );

  const handleSelect = useCallback(
    (id: string) => {
      onSelect(id);
    },
    [onSelect]
  );

  return (
    <ul>
      {sortedProducts.map((product) => (
        <li key={product.id}>
          <button onClick={() => handleSelect(product.id)}>
            {product.name}
          </button>
        </li>
      ))}
    </ul>
  );
});

This component uses three memoization mechanisms to avoid unnecessary work.

With React Compiler enabled, in many cases, we can write the same component more naturally:

ShareShare on XShare on Telegram

Last updated October 2026

A

Amir Esmaeilzadeh

Front-end Developer

Front-End Developer with 3+ years of experience building modern, responsive websites and web applications, focused on React, Next.js, performance, and user experience.

PreviousInside React Server Components: From Server Execution to Browser InteractivityNextTanStack Redact: A Smaller Runtime for React Applications

Related posts

  • Inside React Server Components: From Server Execution to Browser InteractivityOctober 2026
  • TanStack Redact: A Smaller Runtime for React ApplicationsOctober 2026
فا
function ProductList({
  products,
  onSelect,
}: {
  products: Product[];
  onSelect: (id: string) => void;
}) {
  const sortedProducts = products.toSorted(
    (a, b) => a.price - b.price
  );

  const handleSelect = (id: string) => {
    onSelect(id);
  };

  return (
    <ul>
      {sortedProducts.map((product) => (
        <li key={product.id}>
          <button onClick={() => handleSelect(product.id)}>
            {product.name}
          </button>
        </li>
      ))}
    </ul>
  );
}

The Compiler analyzes this code and can generate the appropriate memoization logic during the build process.

The goal is not to change how developers think about React components. It is to reduce the amount of manual performance-related code they need to maintain.

How Does Automatic Memoization Work?

Before understanding React Compiler, it helps to understand memoization.

Memoization is an optimization technique that caches the result of a calculation or preserves a reference so that unchanged inputs do not require unnecessary recomputation.

React Compiler performs this optimization at build time.

At a high level, the compiler analyzes your source code, builds an internal representation, tracks data flow and mutability, and generates memoization logic for expressions and components that can be optimized.

This can include:

  • Skipping unnecessary cascading re-renders.
  • Caching expensive calculations.
  • Preserving function and value references when appropriate.
  • Analyzing actual dependencies in a component.
  • Optimizing individual expressions rather than treating an entire component as one unit.

One important difference from manual memoization is that the compiler can optimize smaller sections of a function, including conditional sections, with more precise dependency analysis.

Build-Time Optimization vs. Manual Memoization

FeatureManual MemoizationReact Compiler
Optimization decisionsWritten by developersGenerated during build
Hook requirementsUsually requiredOften unnecessary
Dependency managementDeveloper-managedCompiler analysis
Code maintenanceCan become complexUsually simpler
Fine-grained controlDirect and explicitAutomatic, with opt-in controls

This does not mean the compiler is universally better in every situation. The two approaches provide different levels of control.

Do We Still Need useMemo, useCallback, and React.memo?

The short answer: not in many common cases, but these APIs are not deprecated.

React Compiler reduces the need for manual memoization. It does not remove the existing APIs or make them useless.

useMemo

useMemo caches the result of a calculation between renders.

Without relying on compiler optimization, we might write:

const filteredUsers = useMemo(() => {
  return users.filter((user) => user.active);
}, [users]);

With React Compiler, we can often write:

const filteredUsers = users.filter((user) => user.active);

The compiler can analyze the calculation and determine when its result needs to be recomputed.

useCallback

useCallback preserves a function reference between renders.

Traditional implementation:

const handleSubmit = useCallback(() => {
  submitForm(formData);
}, [formData]);

With React Compiler:

const handleSubmit = () => {
  submitForm(formData);
};

In many cases, the compiler can handle function memoization automatically.

React.memo

React.memo prevents a component from re-rendering when its props have not changed.

const UserCard = memo(function UserCard({ user }: Props) {
  return <div>{user.name}</div>;
});

React Compiler can automatically apply equivalent optimizations to components that it can safely analyze.

When Are These APIs Still Useful?

There are situations where manual memoization remains valuable:

  1. When you need precise control over a cached value or function.
  2. When reference stability matters for an Effect dependency.
  3. When your application does not have React Compiler enabled.
  4. When maintaining an existing codebase where removing memoization could change compilation output or runtime behavior.

The official React guidance is straightforward: for new code, rely on the compiler by default and use useMemo or useCallback when you need more precise control.

For existing codebases, do not remove all existing memoization blindly. Test the behavior and performance before making changes.

Installing React Compiler

React Compiler is designed to work best with React 19, but it also supports React 17 and 18 with the appropriate compiler runtime and configuration.

Start by installing the compiler as a development dependency:

npm install -D babel-plugin-react-compiler

Or with pnpm:

pnpm add -D babel-plugin-react-compiler

Setting Up React Compiler with Vite

For newer versions of @vitejs/plugin-react, the official React documentation provides a setup using reactCompilerPreset and @rolldown/plugin-babel.

First, install the additional package:

npm install -D @rolldown/plugin-babel

Then configure vite.config.ts:

import { defineConfig } from "vite";
import react, {
  reactCompilerPreset,
} from "@vitejs/plugin-react";
import babel from "@rolldown/plugin-babel";

export default defineConfig({
  plugins: [
    react(),
    babel({
      presets: [reactCompilerPreset()],
    }),
  ],
});

This setup targets newer versions of the Vite React plugin. Older versions may use a different Babel configuration, so check your installed package versions before applying the configuration.

Setting Up React Compiler with Next.js

React Compiler support is stable in Next.js 16 and no longer requires an experimental configuration flag.

Install the compiler:

npm install -D babel-plugin-react-compiler

Then enable it in next.config.ts:

import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  reactCompiler: true,
};

export default nextConfig;

That's it. Next.js will enable React Compiler as part of its build pipeline.

Earlier Next.js versions have different support and configuration details. The official documentation also describes support starting with Next.js 15.3.1.

How to Verify That React Compiler Is Working

Installing the package does not automatically guarantee that the compiler is enabled correctly.

One of the easiest ways to verify its activity is through React Developer Tools.

  1. Install the React Developer Tools browser extension.
  2. Run your application in development mode.
  3. Open the Components panel.
  4. Inspect the components that have been compiled.

Optimized components may display a Memo ✨ badge.

You can also inspect the generated build output. Compiled code may contain imports from react/compiler-runtime and generated caching logic.

Incremental Adoption in Production Applications

If you are working on a large production application, enabling the compiler across the entire codebase without testing is not the best starting point.

React Compiler supports incremental adoption, allowing teams to introduce it gradually.

For example, you can begin with newly developed features or specific directories, validate the results, and expand compiler coverage over time.

One available approach is compilationMode: "annotation".

In this mode, only components and Hooks explicitly marked with the "use memo" directive are compiled.

function ProductList({ products }: Props) {
  "use memo";

  const sortedProducts = products.toSorted(
    (a, b) => a.price - b.price
  );

  return (
    <ul>
      {sortedProducts.map((product) => (
        <li key={product.id}>{product.name}</li>
      ))}
    </ul>
  );
}

You can also temporarily exclude a component from compilation:

function LegacyComponent() {
  "use no memo";

  // This component will be skipped by the compiler.
  return <div>Legacy component</div>;
}

These options are particularly useful when migrating large applications or introducing the compiler into an established codebase.

Limitations and Production Considerations

React Compiler offers meaningful benefits, but it should not be treated as a universal solution to every performance problem.

1. It Does Not Replace Good Architecture

If a component is too large, state is placed at the wrong level, or unnecessary data flows through the component tree, the compiler cannot automatically fix every architectural problem.

2. The Rules of React Still Matter

The compiler relies on React's programming model to analyze components safely.

Patterns such as mutating props or state, incorrectly using Hooks, or performing side effects during rendering can prevent parts of your code from being optimized.

3. Build Times May Increase

Because the compiler analyzes and transforms source code, enabling it may increase development and production build times.

This overhead should be evaluated alongside the performance improvements experienced by users.

4. Memoization Does Not Solve Every Performance Problem

React Compiler focuses on render-related optimization and calculations within React components.

It does not automatically solve issues such as:

  • Network bottlenecks.
  • Large JavaScript bundles.
  • Expensive API requests.
  • Unoptimized images.
  • Poor data-fetching strategies.
  • Long-running main-thread tasks.
  • Inefficient DOM operations.

You should continue using tools such as React Profiler and Chrome Performance Panel to identify actual bottlenecks.

Does React Compiler Make Every Application Faster?

No. The actual improvement depends on the application's architecture, rendering patterns, expensive calculations, and existing optimization strategies.

If an application is already well optimized, you may not notice a significant difference.

On the other hand, applications with excessive manual memoization or unnecessary cascading re-renders may benefit considerably.

The only reliable way to evaluate the impact is to measure performance before and after enabling the compiler under comparable conditions.

Final Thoughts

React Compiler represents an important step forward in the React developer experience.

By automating much of the memoization process, it allows developers to write simpler and more maintainable code without manually optimizing every component and function.

However, it does not replace a solid understanding of React, good component architecture, proper state management, or performance profiling.

My recommendations:

  • Consider enabling React Compiler in new React 19 applications.
  • Use incremental adoption when introducing it into existing projects.
  • Do not remove existing memoization without testing.
  • Measure real-world results with profiling tools.
  • Focus on application architecture rather than simply reducing the number of memoization Hooks.

Ultimately, the goal is not to eliminate every useMemo and useCallback call. The goal is to build faster applications with less unnecessary complexity.

References and Further Reading

  • React Compiler — Official Documentation
  • React Compiler Installation
  • React Compiler Incremental Adoption
  • React Compiler v1.0 Announcement
  • Next.js React Compiler Configuration
  • React useMemo
  • React useCallback
  • React memo

Written for frontend developers interested in modern React performance optimization and building maintainable applications.