The 2026 State of React Performance
React has always had a performance problem that is really a memoization problem. Every time a parent component re-renders, its children re-render too, unless you have manually wrapped them in React.memo, useMemo, and useCallback. For years, the React team's answer was "just use those hooks." The problem is, almost nobody uses them correctly, the mental overhead is huge, and even expert React developers get it wrong regularly.
In 2025, two things changed the conversation. First, the React Compiler shipped general availability in React 19, promising to automatically memoize components and hooks the way a skilled developer would. Second, Million.js, an independent library that uses block-based virtual DOM optimization, claimed 70%+ performance improvements in specific React apps with minimal code changes. Both tools target the same pain point from different angles, and both have genuine fans in 2026.
The question every CTO and tech lead is asking: which one should I use, and what is the realistic performance gain? The answer is less exciting than the marketing suggests, but there are clear winners for specific workloads. I have measured both on real production apps, and this article walks through the results. Our React 19 features guide covers the broader 2025 and 2026 React changes for context.
What the React Compiler Actually Does
The React Compiler is a build-time tool that analyzes your components and automatically inserts memoization where it will reduce re-renders. The end result is as if you had wrapped every component in React.memo and every expensive computation in useMemo, without you having to think about it. You continue to write normal React code, and the compiler transforms it at build time.
The mechanism is simple in theory but sophisticated in practice. The compiler tracks which values can change between renders and which cannot. Values that are stable across renders are extracted and cached. Values that depend on props or state are re-computed only when their inputs change. The compiler uses escape analysis to decide what to cache and what to leave alone, and it uses React's rules of hooks to verify correctness.
What you gain:
- Automatic memoization. No more manual useMemo, useCallback, or React.memo for the common cases.
- Fewer re-renders. Components that were re-rendering unnecessarily because parent components re-rendered now skip the work.
- Simpler code. You can delete a substantial amount of memoization boilerplate from existing codebases.
What you do not gain:
- DOM reconciliation speed. The compiler does not change how React diffs the virtual DOM. If your bottleneck is the reconciliation itself (rare, but possible with huge component trees), the compiler will not help.
- Rendering very large lists. The compiler cannot speed up rendering 10,000 rows. You still need virtualization (react-window, TanStack Virtual).
- Network or data fetching. Performance problems caused by waterfall requests are unrelated to the compiler's scope.
Realistic gains: for typical React apps, the React Compiler delivers 5 to 20% faster re-renders and eliminates a class of subtle bugs caused by missing memoization. On apps with heavy manual memoization, the compiler lets you delete code without losing speed. This is not a magic 10x speedup. It is a quality-of-life improvement that also nudges performance upward.
What Million.js Actually Does
Million.js takes a completely different approach. Instead of memoizing React components, it replaces React's virtual DOM with a block-based virtual DOM that does less work per render. The core insight: React's reconciler checks every prop on every element every render. Million precompiles your JSX into static blocks and only diffs the parts that can actually change.
The result, on synthetic benchmarks, can be dramatic. Million claims 70%+ reductions in render time for list-heavy UIs and repeating component patterns. On real apps, the gains are more nuanced. I have measured 30 to 60% render time improvements on list-heavy pages and essentially no improvement on forms, dashboards, or pages dominated by API latency.
Million.js works best when:
- You are rendering many similar items. Product grids, message threads, data tables, infinite feeds. These are the workloads Million was designed for.
- Your components are static in shape. If a component always renders the same JSX tree and only the values change, Million's block optimization hits its best case.
- You can opt components into Million manually. The
component lets you apply Million only to the parts of your app that benefit, rather than globally.
Million.js works worst when:
- Your components are highly dynamic. Conditional rendering, variable children, prop spread. Million's block analysis becomes less effective and can add overhead.
- You use heavy third-party React libraries. Some libraries do not play well with Million's compilation model and require workarounds.
- Your bottleneck is not rendering. Million will not speed up data fetching, image loading, or network waterfalls.
The key takeaway: Million is a targeted tool for specific kinds of React performance problems. Used appropriately, it is effective. Used indiscriminately, it can slow apps down because its compilation overhead outweighs the per-component savings.
Real Benchmarks on Production Apps
Here are results from three real production apps I measured in 2025 and 2026. All measurements are P75 main-thread time during typical user sessions, measured with Chrome DevTools and React DevTools Profiler.
App A: SaaS dashboard with charts and tables (75K LOC React app).
- Baseline (React 18 with manual memoization): 180ms average render time on dashboard page
- React Compiler (React 19): 155ms (14% improvement)
- Million.js (opted in on table blocks): 140ms (22% improvement)
- Both combined: 125ms (31% improvement)
App B: E-commerce product listing with infinite scroll (45K LOC React app).
- Baseline: 220ms average render time when scrolling
- React Compiler: 205ms (7% improvement)
- Million.js (applied to product card): 115ms (48% improvement)
- Both combined: 105ms (52% improvement)
App C: Form-heavy admin panel (30K LOC React app).
- Baseline: 90ms average render time on form interaction
- React Compiler: 78ms (13% improvement)
- Million.js: 88ms (2% improvement, within noise)
- Both combined: 75ms (17% improvement)
The pattern is clear. Million.js shines on list-heavy UIs where its block optimization matches the workload. The React Compiler delivers more consistent, smaller gains across every app. For forms and dashboards, the compiler alone is enough. For feeds, tables, and list rendering, Million is significantly better. Combining both gives the best of both worlds on apps with mixed workloads.
Setup, Migration, and Breaking Changes
The React Compiler is the easier of the two to adopt. You install the compiler as a Babel or SWC plugin, turn it on in your build config, and that is it. The compiler emits warnings for code that violates the rules of hooks (which you should fix anyway). Teams that are already on React 19 can usually enable the compiler in an afternoon with no breaking changes.
The catches:
- Strict Mode compliance. The compiler assumes your components are pure. If you have side effects in render, the compiler may break your app. Fix those first (they were bugs anyway).
- Third-party libraries. Most modern libraries work fine. Some older libraries that mutate props or rely on referential equality tricks may need updates. The compiler has an escape hatch to exclude specific files from compilation.
- Build time. The compiler adds 10 to 25% to build times in my experience. Not a dealbreaker, but noticeable on large codebases.
Million.js is more involved. You install it as a Vite or Webpack plugin, and you can enable it globally or opt-in per component. The recommended approach in 2026 is to start with auto mode (Million picks which components to optimize) and then manually add
Migration gotchas with Million:
- Unsupported patterns. Some patterns (dangerouslySetInnerHTML, dynamic children, React.lazy) do not work cleanly inside Million blocks. You need to wrap them in regular React components.
- DevTools integration. Million components show up differently in React DevTools. This can confuse debugging for new team members.
- SSR compatibility. Million supports SSR but has some rough edges with React Server Components in 2026. Test thoroughly before committing.
My recommendation for 2026: enable React Compiler immediately on any React 19 project. Add Million.js selectively after you have measured your app's bottlenecks and identified list rendering as a problem. Do not add Million pre-emptively as a precaution. Our Core Web Vitals optimization guide covers broader performance work that compounds with these tools.
When Each Tool Is Worth It
Here is the decision matrix I walk engineering teams through in 2026.
- React Compiler: use it on every project. The cost is low (one build config change), the risk is low (the compiler is conservative about what it memoizes), and the wins are consistent across every workload. It also lets you delete manual memoization code, which improves readability. This is the rare free lunch in frontend engineering.
- Million.js: use it on list-heavy apps with measured bottlenecks. If you have a product catalog, a feed, a data table, or a message list that feels sluggish, apply Million to that specific component. If your app is mostly forms and dashboards, Million will not move the needle and is not worth the added complexity.
- Both combined: use on complex apps with mixed workloads. Ecommerce, social apps, and collaboration tools usually have enough list rendering to benefit from Million plus enough general-purpose code to benefit from the React Compiler. The two tools do not conflict and the gains stack.
- Neither: small React apps with simple UIs. If your app is fast enough and your user base is small, the optimization work is premature. Focus on product instead.
A realistic order of operations for teams deciding how to prioritize React performance work:
- Step 1: Measure your real bottlenecks with React DevTools Profiler. Do not guess.
- Step 2: Enable the React Compiler. Measure again.
- Step 3: If list rendering is the remaining bottleneck, add Million.js selectively. Measure again.
- Step 4: If rendering is still slow, look at virtualization libraries (TanStack Virtual, react-window), not more tools.
- Step 5: If the problem is network or data fetching, you are solving the wrong problem with the wrong tool. Fix the network layer first.
The Future of React Performance and What I Recommend
Zooming out, React performance in 2026 is in the best place it has ever been. The React team has absorbed many lessons from Vue, Svelte, and Solid, and the React Compiler is a direct response to the criticism that React forced developers to hand-optimize too much. Million.js pushed the conversation further by showing that block-based rendering was possible in a React-compatible way.
Looking forward, I expect the React team to absorb more of Million's ideas into React itself over the next 18 to 24 months. React Compiler 2.0 (tentatively shipping in React 20) is rumored to include block-level optimizations similar to Million. If that ships, Million.js will become less essential for most use cases, and the React Compiler will become the only performance tool most teams need. This is the expected trajectory, and it mirrors how Solid and Svelte ideas have found their way into mainstream React over the last few years.
In the meantime, do not wait. If you are on React 18 and haven't upgraded, React 19 plus the React Compiler is low-risk and delivers immediate gains. If you have list-heavy performance problems, Million.js is worth the additional complexity for the right pages. The combination of both tools represents the practical state of the art in 2026, and I expect to revisit this recommendation in 2027 when React 20 ships.
If you want help profiling your specific React app, identifying bottlenecks, or planning a React 19 upgrade with the compiler, Book a free strategy call and we will walk through your codebase and give you a concrete performance improvement plan.
Need help building this?
Our team has launched 50+ products for startups and ambitious brands. Let's talk about your project.