React Compiler: No More useMemo and useCallback

React Compiler: No More useMemo and useCallback

React Compiler automatically optimizes your components at build time. No more useMemo, useCallback, or React.memo. Learn how to set it up and what you need to know.

Aurora Scharff

Aurora Scharff

January 13, 2026

React Compiler takes away the mental burden of performance optimization. You no longer need to think about useMemo, useCallback, or React.memo. The compiler handles it for you automatically.

This article covers what React Compiler does, how to set it up, and what you need to know to use it effectively.

The Problem: Manual Memoization

Before React Compiler, optimizing performance meant wrapping values and components in memoization hooks:

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

const ProductList = memo(function ProductList({ products, onSelect }) {
  const sortedProducts = useMemo(() => {
    return products.slice().sort((a, b) => a.name.localeCompare(b.name));
  }, [products]);

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

  return (
    <ul>
      {sortedProducts.map(product => (
        <ProductItem key={product.id} product={product} onSelect={handleSelect} />
      ))}
    </ul>
  );
});

    

This works, but it's tedious. You have to decide where memoization helps, manage dependency arrays correctly, and remember to wrap components in memo. It's easy to make mistakes, and the extra code clutters your components.

The Solution: Automatic Optimization

With React Compiler, you write the straightforward version:

      function ProductList({ products, onSelect }) {
  const sortedProducts = products.slice().sort((a, b) => a.name.localeCompare(b.name));

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

  return (
    <ul>
      {sortedProducts.map(product => (
        <ProductItem key={product.id} product={product} onSelect={handleSelect} />
      ))}
    </ul>
  );
}

    

The compiler analyzes your code at build time and adds the memoization automatically. You get the same performance benefits without the mental overhead.

Setting Up React Compiler

React Compiler is a Babel plugin that transforms your code at build time. The setup depends on your build tool.

Installation

First, install the compiler as a dev dependency:

      npm install -D babel-plugin-react-compiler@latest

    

Vite Setup

If you're using Vite with @vitejs/plugin-react, add the compiler to the Babel plugins:

      // vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [
    react({
      babel: {
        plugins: ['babel-plugin-react-compiler'],
      },
    }),
  ],
});

    

Next.js Setup

Next.js 16 has built-in stable support for React Compiler. Just enable it in your config:

      // next.config.ts
const nextConfig = {
  reactCompiler: true,
};

export default nextConfig;

    

Next.js includes a custom SWC optimization that only applies the compiler to files with JSX or React Hooks, keeping builds fast.

React 17 and 18

The compiler works best with React 19, but it also supports React 17 and 18. You'll need to install a runtime package that provides the compiler's internal APIs:

      npm install react-compiler-runtime@latest

    

Then configure the target version in your Babel or Vite config:

      // In your babel/vite config
['babel-plugin-react-compiler', { target: '18' }] // or '17'

    

For other build tools like Webpack, Expo, React Router, Rspack, or Rsbuild, see the installation docs.

Checking That It Works

Open React DevTools in your browser. Components optimized by the compiler show a "Memo ✨" badge next to their name. If you see the sparkle emoji, the compiler is working.

The One Requirement: Follow the Rules of React

React Compiler relies on your code following the Rules of React. These aren't new rules. They're the same conventions React has always recommended:

  • Components must be idempotent—given the same props, state, and context, a component should always return the same output
  • Props, state, and values passed to hooks are immutable—never mutate them directly, always create new objects or arrays
  • Side effects must run outside of render—use event handlers or useEffect, not code that runs during rendering
  • Only call hooks at the top level—not inside conditions, loops, or nested functions

If you're already writing React the "React way," the compiler should work without issues. If you have code that breaks these rules, the ESLint plugin will help you find it.

ESLint Plugin

The familiar eslint-plugin-react-hooks has been upgraded with compiler-powered lint rules. In addition to the classic rules-of-hooks and exhaustive-deps rules, the plugin now surfaces React Compiler diagnostics. These help you catch patterns that break memoization or that the compiler can't optimize, like mutating props, reading refs during render, or calling setState in effects. You can use it even if you haven't adopted the compiler yet.

      npm install -D eslint-plugin-react-hooks@latest

    

Then add it to your ESLint config:

      // eslint.config.js
import reactHooks from 'eslint-plugin-react-hooks';

export default [
  reactHooks.configs.flat.recommended,
];

    

Here are some examples of what the linter will catch:

      // ❌ Calling setState during render causes infinite loops
function Counter() {
  const [count, setCount] = useState(0);
  setCount(count + 1); // Error: setState in render
  return <div>{count}</div>;
}

// ❌ Reading a ref during render is unsafe
function Input() {
  const inputRef = useRef(null);
  const value = inputRef.current?.value; // Error: ref access in render
  return <input ref={inputRef} />;
}

// ❌ Mutating props breaks memoization
function List({ items }) {
  items.sort(); // Error: mutating props
  return <ul>{items.map(item => <li key={item}>{item}</li>)}</ul>;
}

    

This plugin works independently of the compiler, so you can use it to improve your code and prepare for compiler adoption even before enabling it.

Adopting Gradually

You don't have to enable the compiler for your entire codebase at once. Start with a specific folder:

      // babel.config.js
module.exports = {
  overrides: [
    {
      test: './src/features/**/*.{js,jsx,ts,tsx}',
      plugins: ['babel-plugin-react-compiler'],
    },
  ],
};

    

Test that everything works, then expand to more folders over time.

Opting Out Specific Components

If a component behaves unexpectedly after compilation, you can exclude it:

      function ProblematicComponent() {
  "use no memo";

  // Component code here
}

    

The "use no memo" directive tells the compiler to skip this component. Use this as a temporary fix while you investigate the issue.

What About Existing useMemo and useCallback?

You can leave them in place. The compiler works alongside existing memoization, so there's no rush to remove manual optimizations. For new code, just write it without memoization and let the compiler handle it.

Common Questions

Do I need to change how I write code? No. Write your components normally. The compiler optimizes them automatically.

Will it break my app? The compiler is designed to skip code it can't safely optimize. If something does break, use "use no memo" to exclude that component and report the issue.

Is it production-ready? Yes. React Compiler v1.0 is stable and has been running in production at Meta (including Meta Quest Store) with measurable performance improvements.

Should new projects use it? Yes. Expo SDK 54 enables it by default in the project template, and Next.js 16 has stable built-in support (just add reactCompiler: true to your config). For new projects, there's no reason not to use it.

Conclusion

React Compiler removes the cognitive burden of manual memoization. Instead of deciding where to add useMemo, useCallback, and memo, you write straightforward code and let the compiler optimize it.

To get started: install the plugin, add it to your build config, check DevTools for the ✨ badge, and use the ESLint plugin to catch any issues. That's it.


Sources:

More certificates.dev articles

Get the latest news and updates on developer certifications. Content is updated regularly, so please make sure to bookmark this page or sign up to get the latest content directly in your inbox.

Looking for Certified Developers?

We can help you recruit Certified Developers for your organization or project. The team has helped many customers employ suitable resources from a pool of 100s of qualified Developers.

Let us help you get the resources you need.

Contact Us
Customer Testimonial for Hiring
like a breath of fresh air
Everett Owyoung
Everett Owyoung
Head of Talent for ThousandEyes
(a Cisco company)