The React Compiler

The React 7,897 Compiler inserts the memoization you would otherwise write by hand with useMemo and useCallback (Memoization and Compiler). Next.js 16 10,514 made support stable; the compiler still runs as a Babel 41,624 plugin, so it is an install — npm 2,036 install -D babel-plugin-react-compiler — plus reactCompiler: true in next.config.ts. Run babel-plugin-react-compiler 1.0.0 over an ordinary filtering Client Component:

app/memo-demo/filter.tsx before compilationTSX
export function Filter({ items }: { items: string[] }) {
  const [query, setQuery] = useState('')
  const matches = items.filter((item) => item.includes(query))
  return <div>
    <input value={query} onChange={(e) => setQuery(e.target.value)} />
    <ul>{matches.map((m) => <li key={m}>{m}</li>)}</ul>
  </div>
}
Output
import { c as _c } from "react/compiler-runtime";
export function Filter(t0) {
  const $ = _c(14);
  const { items } = t0;
  const [query, setQuery] = useState("");
  if ($[0] !== items || $[1] !== query) {
    let t3;
    if ($[4] !== query) { t3 = item => item.includes(query); $[4] = query; $[5] = t3; }
    else { t3 = $[5]; }
    const matches = items.filter(t3);
    ...

_c(14) allocates a fourteen-slot cache on the component's fiber; each slot holds one value and the input it was computed from. Nothing is recomputed unless its own inputs changed — the inline onChange arrow, the filtered array and every JSX element are cached independently. Writing that by hand is possible and nobody does it.

Two things matter in practice. Babel is slower than SWC 553,439 , so Next.js runs an SWC pre-pass that sends only files containing JSX or hooks to Babel; the cost is real but small. And the compiler skips code it cannot prove safe, such as a component that mutates its props. If a wholesale switch is too big, use reactCompiler: { compilationMode: 'annotation' }: components then need a 'use memo' directive in their body to be compiled, and 'use no memo' opts one back out.