Author : Mykhailo Hanol
The Virtual DOM (VDOM) has been a foundational technology in frontend development for over a decade, but its reliance on coarse-grained reconciliation introduces performance overhead. This paper investigates an alternative paradigm: fine-grained reactivity via signals. A custom benchmark suite was developed to quantitatively compare two identical applications, one built with React (VDOM) and one with Solid.js (signals), across six common operational scenarios. Measurements of DOM mutations, update latency, memory consumption, and main-thread blocking tasks reveal that the signals-based architecture reduces DOM mutations by up to 99.9%, lowers heap usage by over 70%, and decreases update latency by up to 94%. These findings demonstrate that fine-grained reactivity offers a more performant and efficient foundation for modern user interfaces, suggesting a significant architectural evolution for the field.
Virtual DOM: Today’s industry standard
The VDOM concept was popularized by React in 2013 and later adopted or adapted by frameworks like Vue. Instead of updating the DOM directly, frameworks maintain an in-memory tree that represents the UI. On each state change, the framework re-renders components to produce a new virtual tree, then reconciles it against the previous version, applying only the differences to the real DOM. This abstraction made large-scale, declarative UI development feasible and quickly became the dominant model. Wikipedia: Virtual DOM · React Render & Commit · React Internals FAQ · Vue Rendering Mechanism · Vue Render Function · Vue key attribute
But like any abstraction, the Virtual DOM carries fundamental costs:
- Re-render by assumption: On any state change, a component and its descendants re-run, even if only a tiny part of the state was relevant.
- Unknown change scope: The framework does not know which binding changed, so it regenerates and diffs whole subtrees “just in case.”
- Reconciliation overhead: Tree diffing is O(n) relative to subtree size, not O(1) to the actual change.
- Developer optimization burden: Without useMemo, useCallback, or splitting components, entire trees re-render. Many capable engineers new to React are surprised to discover that updating a parent state without memoization causes all children to re-render, even if they don’t depend on that state.
This model can deliver acceptable performance for small apps, but at scale it often produces thousands of unnecessary DOM mutations, heavy GC pressure, and long tasks that degrade responsiveness.
Signals: A Fine-Grained Alternative
Signals-based frameworks take the opposite approach. Instead of assuming “everything might have changed,” they operate on the principle: “only update exactly what did change.”
A signal is a reactive primitive that stores a value and tracks who reads it. When the signal updates, only those specific computations or DOM bindings that depend on it re-run. There is no global re-render and no tree diffing. Updates are constant-time and localized.
Fundamental mental model difference
- Virtual DOM: “We don’t know what changed, so let’s re-render the component tree and reconcile it to check all bindings.”
- Signals: “We know exactly what changed, so we update only those bindings that use the changed signal.”
Solid.js embodies this model completely, while Angular is in the process of transitioning its reactivity system toward signals. Solid’s documentation describes its reactive primitives in detail (Solid Reactivity API · Intro to Reactivity · Solid Reactivity Guide). Angular introduced Signals in v16 (Angular v16 Announcement), continues to stabilize them in v20 (Angular v20 Announcement), and has explicitly positioned signals as the future of its reactivity model (Angular Vision for the Future; Angular Signals Guide).
Internal Mechanics Compared
Virtual DOM (React, Vue)
- State changes trigger a render phase: component functions run, producing a new virtual tree.
- A diffing algorithm (reconciliation) compares old vs. new trees.
- A commit phase applies minimal patches to the real DOM.
- Keys (key attribute in Vue/React) guide reconciliation to avoid tearing down entire lists.
- Optimization requires developers to split components and use memoization.
Signals (Solid, Angular Signals)
- Each signal holds a value and maintains a dependency list of subscribers.
- When a computation (e.g. a DOM text binding) reads a signal, a dependency edge is recorded.
- When the signal updates, only the dependent computations are re-run, directly mutating the DOM node or value they control.
- No virtual tree is created, no reconciliation is needed.
- The system guarantees correctness by construction: only what actually changed updates.
A Quantitative Benchmark Suite for Comparative Analysis
These two approaches are philosophically and technically different, but how do they compare in practice? To answer this, I built a pair of identical applications — a React VDOM dashboard and a Solid.js signals dashboard — and measured their behavior under controlled workloads.
I created a benchmarking harness in Puppeteer that ran six scenarios (filtering, incremental updates, bulk insertions, bulk removals, sorting, idle). Metrics included DOM mutations, update latency, heap size, and long task duration. Each scenario was repeated 10 times per framework (120 runs total)
To establish a baseline performance metric reflecting the default behavior of the Virtual DOM architecture, the React implementation was benchmarked in its pure state, without manual performance optimizations such as useMemo or useCallback. This intentional methodological choice allows for a direct comparison of the foundational efficiency of the two rendering paradigms—coarse-grained VDOM reconciliation versus fine-grained signals—isolating the framework’s inherent overhead from developer-applied micro-optimizations. The results thus represent the architectural ‘out-of-the-box’ performance
Benchmarks Architecture
- React Implementation: Built with Virtual DOM using useState and useEffect. No performance optimizations (useMemo, useCallback) were applied, by design.
- Solid Implementation: Built with fine-grained signals (createSignal, createMemo) and reactive primitives. No Virtual DOM overhead.
- Shared Components: Identical UI, styling, and data structures (filters, KPI header, 10k-row data grid, sort, log).
- Measurement: Puppeteer-controlled Chromium automation, 10 runs per scenario per framework, using MutationObserver, PerformanceObserver, and Chrome Memory API.
Testing Scenarios and Metrics
The benchmark includes six scenarios covering filtering, incremental updates, bulk operations, sorting, and idle monitoring:
- S1_FILTER – Region Filter Change
Operation: Single dropdown selection (EU region).
Purpose: Test basic filtering and re-rendering.
Complexity: Low.
- S2_UPDATE_1PCT – Incremental Updates
Operation: 50 consecutive 1% row updates with 100ms intervals.
Purpose: Evaluate continuous update handling.
Complexity: High (frequent state changes).
- S3_INSERT_1K – Bulk Insertion
Operation: Insert 1,000 rows into the grid.
Purpose: Test large-scale DOM expansion.
Complexity: High.
- S4_REMOVE_1K – Bulk Removal
Operation: Remove 1,000 rows.
Purpose: Test large-scale DOM reduction.
Complexity: High. - S5_SORT_COL – Column Sorting
Operation: 5 consecutive price column sorts.
Purpose: Evaluate dataset reordering.
Complexity: Very High.
- S6_IDLE_30S – Idle Monitoring
Operation: 30-second idle period.
Purpose: Baseline measurement, memory leak detection.
Complexity: Minimal.
Metrics Measured
- DOM Mutations (via MutationObserver)
- Update Latency (milliseconds from action to settled DOM)
- Heap Size (MB, via Chrome Memory API)
- Long Task Count (>50ms blocking tasks)
- Long Task Duration (total ms blocked)
Benchmark Results
The data clearly shows the performance implications of both models. Below I present the quantitative results and charts (placeholders included from the generated HTML).
Update Latency

- React median latencies ranged from 1,035ms to 8,298ms.
- Solid.js reduced this to 473ms to 3,083ms in most cases.
- The largest gap appeared in continuous updates (S2_UPDATE_1PCT): Solid.js was 93.5% faster.
Long Task Count & Duration


- React often generated dozens of long tasks, with blocking durations over 8s.
- Solid.js kept this to 1–2 tasks with durations under 1s in most scenarios.
Memory Usage

- React’s heap usage peaked at 2.4 GB during idle.
- Solid.js stayed around 675 MB.
- Consistently, Solid.js reduced heap usage by 70–75%.
DOM Mutations

- React generated tens of thousands of DOM mutations per operation (e.g., 101,997 for sorting).
- Solid.js reduced this to single digits (7).
- Overall, Solid.js achieved a 99.9% reduction in DOM mutations.
Results
Sample Size
10 runs × 6 scenarios × 2 frameworks = 120 total measurements.
Executive Summary
- DOM Mutations: Solid.js reduced mutations by 99.9% vs React.
- Memory Usage: Solid.js consumed 70–75% less heap memory.
- Update Latency: Solid.js improved operation speed by 30–94%.
- Long Tasks: Solid.js reduced blocking task frequency and duration by up to 98%.
DOM Mutations Comparison
| Scenario | React (Median) | Solid (Median) | Improvement |
| S1_FILTER | 10,007 | 3 | 3,336:1 |
| S2_UPDATE_1PCT | 25,168 | 52 | 484:1 |
| S3_INSERT_1K | 11,007 | 3 | 3,669:1 |
| S4_REMOVE_1K | 11,010 | 3 | 3,670:1 |
| S5_SORT_COL | 101,997 | 7 | 14,571:1 |
| S6_IDLE_30S | 10,005 | 2 | 5,003:1 |
Insight: Solid achieves near-minimal DOM mutations, while React’s reconciliation triggers tens of thousands—even when idle.
Update Latency
| Scenario | React Median | React P95 | Solid Median | Solid P95 | Improvement |
| S1_FILTER | 1,035ms | 1,323ms | 473ms | 560ms | 54.3% faster |
| S2_UPDATE_1PCT | 8,298ms | 9,371ms | 541ms | 669ms | 93.5% faster |
| S3_INSERT_1K | 1,554ms | 1,653ms | 759ms | 857ms | 51.2% faster |
| S4_REMOVE_1K | 1,361ms | 15,360ms | 661ms | 837ms | 51.4% faster |
| S5_SORT_COL | 4,948ms | 5,688ms | 3,083ms | 3,358ms | 37.7% faster |
| S6_IDLE_30S | 1,036ms | 1,091ms | 720ms | 973ms | 30.5% slower |
Insight: The biggest gap is in continuous updates (S2): Solid is ~15× faster. React’s P95 latency spikes dramatically in removals (15.36s).
Memory Consumption (Heap)
| Scenario | React Median | React P95 | Solid Median | Solid P95 | Reduction |
| S1_FILTER | 264.68MB | 441.04MB | 75.80MB | 121.55MB | 71.4% |
| S2_UPDATE_1PCT | 748.22MB | 955.88MB | 199.74MB | 248.16MB | 73.3% |
| S3_INSERT_1K | 1,235.10MB | 1,417.45MB | 322.25MB | 374.85MB | 73.9% |
| S4_REMOVE_1K | 1,659.76MB | 1,817.85MB | 441.23MB | 485.65MB | 73.4% |
| S5_SORT_COL | 2,133.75MB | 2,329.08MB | 559.64MB | 605.78MB | 73.8% |
| S6_IDLE_30S | 2,472.70MB | 2,568.36MB | 675.05MB | 722.94MB | 72.7% |
Insight: Solid uses ~¼ the memory of React consistently.
Long Task Performance
| Scenario | React Tasks | React Duration | Solid Tasks | Solid Duration | Reduction |
| S1_FILTER | 2 | 1,035ms | 1 | 473ms | 50% fewer |
| S2_UPDATE_1PCT | 51 | 8,298ms | 1 | 541ms | 98% fewer |
| S3_INSERT_1K | 2 | 1,554ms | 2 | 759ms | 51% shorter |
| S4_REMOVE_1K | 2 | 1,361ms | 1 | 661ms | 50% fewer |
| S5_SORT_COL | 6 | 4,948ms | 7 | 3,083ms | ~38% shorter |
| S6_IDLE_30S | 1 | 1,036ms | 1 | 720ms | 31% shorter |
Insight: Continuous updates (S2) show the most dramatic difference: React blocked the main thread with 51 long tasks, Solid reduced this to 1.
Architectural Deep Dive: Why Signals Outperform Virtual DOM
1. Virtual DOM: A Necessary Overhead
The Virtual DOM works by diffing an in-memory representation of the UI to determine UI changes minimalist enough to apply to the real DOM. This enabled powerful declarative UI development, but at the cost of structural inefficiency.
It relies on a two-step cycle—render & reconcile—that repeatedly evaluates render functions and then diffs trees (reconciliation), which is O(n) in subtree size. When a root-state changes, React must re-render entire component subtrees, even when only a small fragment changes.
This approach often forces developers to compensate with micro-optimizations like useMemo, useCallback, and React.memo. My observations align with industry sentiment: even seasoned engineers new to React often overlook these, resulting in widespread full-tree re-renders. This hidden complexity weakens both performance and developer intent.
2. Signals: Surgical Update Precision
Signal-based systems—Solid.js, angular signals, Preact Signals—adopt fine-grained reactivity. Each signal tracks its dependents during reads, and upon updates, only re-executes exactly those dependent computations or DOM bindings. There is no re-render or diffing step.
JavaScript in Plain English: Signals Deep Dive · ToTheNew: Why Signals Could Be the Future
This architecture makes updates constant-time, memory-efficient, and cognitively simpler. You get high performance without worrying about memoization or dependency arrays.
3. Developer Experience (DX): Simplicity over Complexity
Signals reduce the cognitive load significantly:
- No need to craft parcels of code for useMemo or pass props deeply to prevent needless rerenders.
- UI updates are localized: you change a signal; only its dependent parts update.
- You think in terms of what changed, not how to optimize updates.
A dev-blog by Velotio captures this well:
Signals eliminate the need for hooks like useEffect, useMemo, useCallback, drastically simplifying the mental model.
Why Signals Could Be the Future for Modern Web Frameworks
Ecosystem Momentum: Signals on the Rise
- Angular is pivoting toward signals, positioning them as the future of reactivity in its v16–v20 lifecycle.
Angular v16 · v20 · Vision · Guide
- Solid.js is intentionally built without a Virtual DOM. Its creator, Ryan Carniato, argues reactivity alone suffices for modern UIs.
Making the Case for Signals in JavaScript
- Framework comparisons highlight the trade-off between coarse-grained (VDOM) vs fine-grained reactivity: signals excel in performance and predictability.
Builder.io: Reactivity Across Frameworks
Scenarios Revisited: Why Signals Excel
Let’s revisit key scenarios through the lens of architectural intent:
- S2_UPDATE_1PCT – Continuous Updates
- React produces 51 long tasks and ~25k DOM mutations (8.3s median latency).
- Solid executes in ~541ms with ~52 mutations—only the changed rows update.
Insight: Virtual DOM re-renders subtree; signals target only affected bindings.
- React produces 51 long tasks and ~25k DOM mutations (8.3s median latency).
- S5_SORT_COL – Heavy Reordering
- React performs ~102k mutations; Solid handles it in just 7.
Insight: Signals adjust order without rebuilding or diffing the entire table.
- React performs ~102k mutations; Solid handles it in just 7.
- S6_IDLE_30S – True “Idle” Behavior
React still produces 10k mutations; Solid remains near-perfectly stable.
Insight: Signals avoid unnecessary background effects, demonstrating real idle performance.
Scientific Rigor and Limitations
- Sample size: 10 independent runs per scenario.
- Reproducibility: Public code repository and deterministic data.
- Measurement fidelity: DOM, latency, memory, long tasks recorded precisely.
Known limitations:
- Results limited to desktop Chromium; mobile and other browsers not covered.
- React wasn’t optimized via useMemo, intentionally representing common real-world developer behavior.
- Components didn’t use virtualization—this was about raw reactivity costs, not graphic optimizations.
Vision & Practical Impact
Signals are not just faster—they redefine how we architect UIs.
- Applications with frequent updates (e.g., dashboards, data tools): benefit dramatically from reduced mutation and memory overhead.
- Mobile/low-resource contexts: Signal’s memory efficiency improves load times and responsiveness.
- Developer teams: Faster iteration, fewer optimization bugs, clearer mental models.
Angular, Solid, Preact, Qwik—frameworks across the ecosystem are converging on signals as a default future.
Final Thoughts
The results of this benchmarking study demonstrate a compelling trend: fine-grained signals offer clear advantages over the Virtual DOM in terms of DOM efficiency, memory usage, and update latency, particularly in data-intensive scenarios where React’s reconciliation overhead becomes most visible. While React and other Virtual DOM–based frameworks have been instrumental in shaping modern frontend development, our measurements show that Solid.js and similar signal-based approaches achieve far greater precision in updates, eliminating almost all unnecessary mutations and reducing memory consumption by more than two-thirds. Importantly, these gains were observed even without applying React’s optimization patterns such as useMemo or useCallback—an omission that reflects the reality of many production codebases, where engineers (even highly capable ones) may not employ such optimizations consistently. Signals, in contrast, deliver performance as the default rather than as the result of manual tuning. Taken together, these findings suggest that signals are not merely an incremental improvement but a meaningful architectural evolution that simplifies developer experience while unlocking significant performance headroom. The future of frontend frameworks may not hinge on whether signals replace the Virtual DOM outright, but on how quickly teams, frameworks, and the wider ecosystem embrace this paradigm to build faster, leaner, and more predictable applications.
About the author:
Mykhailo Hanol is a Software Engineer with more than seven years of experience building complex and performant web applications. He is passionate about delivering outstanding user experiences while keeping speed, scalability, and efficiency at the core. Over his career, Mykhailo has contributed to projects in diverse domains, including online education, content creation platforms, fintech, e-commerce, and global supply chain systems.
Alongside his professional work, he is actively researching and developing experimental frontend frameworks that explore new paradigms in performance and developer experience, with a particular focus on signals-based reactivity and modern rendering techniques. Through technical writing and data-driven research, he shares insights that help engineering teams adopt cutting-edge approaches to building faster and more efficient applications.
- Ten Ways Small Businesses Can Use Technology for Growth
- The Statistics of Modern Dating: What U.S. Census Data Reveals About “Standards” and the Math of Compatibility
- Transform Your Videos Instantly with Ai Face Swap: The Ultimate AI Video Face Swap Tool for Hyper-Realistic Results
- Mastering Custom Apparel Printing with Modern Crafting Tools