# React Compiler Impact on Memoization Patterns in Instatic: A Complete Guide

> Discover how React Compiler revolutionizes Instatic by eliminating manual memoization. Learn the three exceptions to automatic build-time memoization for CoreBunch/Instatic.

- Repository: [CoreBunch/Instatic](https://github.com/CoreBunch/Instatic)
- Tags: deep-dive
- Published: 2026-08-01

---

**The React Compiler eliminates the need for manual memoization patterns like `useMemo`, `useCallback`, and `React.memo` throughout Instatic by automatically memoizing components and hooks at build time, with only three specific exceptions allowed.**

Instatic is a React codebase that fully embraces the React Compiler to handle performance optimizations automatically. By leveraging build-time analysis via `reactCompilerPreset()` in [`vite.config.ts`](https://github.com/CoreBunch/Instatic/blob/main/vite.config.ts), the project eliminates traditional manual memoization boilerplate while enforcing strict rules about when developers may still use `useCallback` or `React.memo`. Understanding these React Compiler memoization patterns in Instatic helps contributors write cleaner, more maintainable code without sacrificing runtime performance.

## How the React Compiler Automates Memoization in Instatic

The React Compiler performs static analysis during the build process to automatically memoize every component and hook. In [`vite.config.ts`](https://github.com/CoreBunch/Instatic/blob/main/vite.config.ts), the compiler is enabled via `reactCompilerPreset()`, which transforms your code to include stable identities for values, functions, and components without manual intervention.

Because the compiler generates these optimizations automatically, any additional hand-written memoization is considered *noise* and provides no additional performance benefit. The project configures [`react-doctor.config.json`](https://github.com/CoreBunch/Instatic/blob/main/react-doctor.config.json) to downgrade compiler-related warnings to advisory status, acknowledging that the build-time analysis handles memoization concerns that developers traditionally managed manually.

## The "No Manual Memoization" Rule

Instatic enforces a strict prohibition against `useMemo`, `useCallback`, and `React.memo()` throughout the codebase. According to the reference documentation in [`docs/reference/react-compiler.md`](https://github.com/CoreBunch/Instatic/blob/main/docs/reference/react-compiler.md), manual memoization patterns are unnecessary because the compiler already generates stable references for functions and values.

This rule is actively enforced through ESLint and documented in code comments. For example, in [`src/admin/spotlight/SpotlightRoot.tsx`](https://github.com/CoreBunch/Instatic/blob/main/src/admin/spotlight/SpotlightRoot.tsx), you will find explicit comments prohibiting `useMemo` where developers might traditionally reach for it, noting that the React Compiler handles optimization automatically even in complex factory patterns.

## The Three Exceptions Where Manual Memoization Is Allowed

Despite the general prohibition, the Instatic codebase recognizes three legitimate scenarios where manual memoization remains necessary.

### Exception 1: Hook Dependency Arrays

When a function is used inside a hook's dependency array, you must wrap it in `useCallback` to satisfy the `react-hooks/exhaustive-deps` ESLint rule. This ensures the function maintains a stable identity across renders, preventing infinite loops or missed effect executions.

```typescript
export function SearchBox() {
  const [query, setQuery] = useState('');

  // `handleChange` is used in a `useEffect` deps array → must be stable.
  const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
    setQuery(e.target.value);
  }, []); // ← exception 1

  useEffect(() => {
    // Do something with `query` when it changes.
  }, [query, handleChange]);

  return <input value={query} onChange={handleChange} />;
}

```

### Exception 2: Hot-List Components

Components that render recursively or handle high-frequency updates—such as canvas renderers or large tree views—may benefit from an explicit `React.memo` bail-out. This manual memoization prevents unnecessary reconciliation in hot paths where the compiler's automatic memoization might not provide sufficient granularity.

```tsx
// In a tree-renderer where each node is rendered O(N) times.
const NodeRenderer = memo(function NodeRenderer({ node }: { node: TreeNode }) {
  // Rendering logic …
  return <div>{node.label}</div>;
}); // ← exception 2

```

### Exception 3: Compiler Escape Hatches

When the React Compiler encounters a complex closure or pattern it cannot compile, you may use manual `useCallback` with an ESLint disable comment. This escape hatch is reserved for scenarios where the compiler's static analysis fails to determine dependency stability.

```tsx
// The compiler cannot compile this complex closure.
export const complexHandler = useCallback(() => {
  // ...complex logic...
}, []); // eslint-disable-next-line react-compiler/react-compiler

```

## Code Examples: Correct vs. Incorrect Patterns

The following examples demonstrate the memoization patterns enforced throughout the Instatic codebase.

**Correct: Plain function without memoization**

```tsx
export function PageHeader({ title }: { title: string }) {
  // Plain function – the React Compiler will memoize it.
  return <h1>{title}</h1>;
}

```

**Incorrect: Unnecessary manual memoization**

```tsx
const expensiveValue = useMemo(() => computeExpensive(), []); // ❌ drift

```

When exceptions apply, always include a brief comment explaining why manual memoization is necessary, satisfying the lint rules without introducing redundant abstraction layers.

## Lint Gates and Enforcement

Instatic enforces these memoization rules through a dual ESLint configuration defined in [`eslint.config.js`](https://github.com/CoreBunch/Instatic/blob/main/eslint.config.js). The setup combines `eslint-plugin-react-compiler` with `eslint-plugin-react-hooks` to run checks during `bun run lint`.

The compiler plugin identifies code that violates the "no manual memoization" policy, while the hooks plugin ensures that the three exceptions—particularly dependency array stability—are handled correctly. Together, these tools maintain code quality and prevent performance anti-patterns from entering the codebase.

## Summary

- **Automatic memoization**: The React Compiler handles all memoization at build time via `reactCompilerPreset()` in [`vite.config.ts`](https://github.com/CoreBunch/Instatic/blob/main/vite.config.ts), making `useMemo`, `useCallback`, and `React.memo` unnecessary in most cases.
- **Strict prohibition**: Manual memoization is considered noise and is actively removed; reference [`docs/reference/react-compiler.md`](https://github.com/CoreBunch/Instatic/blob/main/docs/reference/react-compiler.md) for the complete policy.
- **Three exceptions**: Only use manual memoization for hook dependency arrays, hot-list recursive components, or compiler escape hatches requiring ESLint disable comments.
- **Enforcement**: `eslint-plugin-react-compiler` and `eslint-plugin-react-hooks` run on `bun run lint` to maintain these standards.
- **Real-world examples**: Files like [`src/admin/spotlight/SpotlightRoot.tsx`](https://github.com/CoreBunch/Instatic/blob/main/src/admin/spotlight/SpotlightRoot.tsx) demonstrate the practical application of these rules with inline documentation.

## Frequently Asked Questions

### Why does Instatic prohibit useMemo and useCallback?

The React Compiler automatically generates stable identities for values and functions during the build process. Manual memoization duplicates this work without providing additional benefits, creating unnecessary abstraction layers and maintenance overhead. As implemented in CoreBunch/Instatic, the compiler's build-time analysis makes hand-written memoization redundant.

### When should I use useCallback in Instatic?

You should only use `useCallback` when a function is referenced in a hook's dependency array to satisfy `react-hooks/exhaustive-deps`, or when the React Compiler cannot compile a specific function and you need to provide an explicit stable reference. Always add a comment explaining the exception when you use this pattern.

### How do I handle functions that the React Compiler cannot compile?

When the compiler fails to analyze a complex closure, wrap the function in `useCallback` with an empty dependency array and add `// eslint-disable-next-line react-compiler/react-compiler` on the preceding line. This escape hatch is reserved for edge cases where static analysis fails, and should be used sparingly according to the guidelines in [`docs/reference/react-compiler.md`](https://github.com/CoreBunch/Instatic/blob/main/docs/reference/react-compiler.md).

### What happens if I accidentally add manual memoization?

The ESLint configuration will flag unnecessary `useMemo`, `useCallback`, or `React.memo` usage during `bun run lint`. These violations must be resolved before merging, either by removing the manual memoization or documenting the specific exception category that applies to your use case. The project treats redundant memoization as technical debt that complicates the codebase without improving performance.