Fine-grained reactivity is on track to become a JavaScript language primitive, and it is aimed directly at the rendering model React and Next.js teams have built on for a decade. The TC39 Signals proposal — championed by Google, Microsoft, and Bloomberg — standardizes observable state graphs that update the DOM by surgical push instead of virtual DOM diffing. This is the most consequential architectural fork in frontend since componentization, and it warrants a hype-free technical analysis.
Signals vs. Virtual DOM: The Reactivity Schism
React's contract is simple: state changes, the component function re-executes, and a reconciliation pass diffs the new virtual tree against the old one. The cost of any update is proportional to the size of the re-rendered subtree, not the size of the change. Signals invert this contract: a write to a reactive cell invalidates only the exact derived values and DOM bindings that depend on it, making update cost proportional to the change itself. The TC39 proposal wants that second model standardized into the language runtime itself.
What Signals Actually Are: The Technical Model
The Core Primitives
- Signal.State — a writable reactive cell. Writing to it marks dependents dirty; no eager computation occurs.
- Signal.Computed — a lazily evaluated derived value. It re-executes only when its dependencies are dirty and someone reads it, then memoizes the result (pull-based evaluation).
- Effects — intentionally excluded from the spec core. Rendering, scheduling, and batching semantics remain framework-owned, which is precisely why Angular, Vue, Solid, Preact, and Qwik can all adopt the standardized graph without surrendering their render architectures.
Graph Semantics: Subscriptions Over Re-Execution
The spec's evaluation algorithm uses dirty flags plus topological rank ordering over the dependency graph. This solves the classic diamond problem — where a value derived from two paths of the same root would recompute twice or observe inconsistent intermediate states — guaranteeing glitch-free, synchronous reads. Unlike React, where any mutation in a component can cascade through its entire subtree, a signal graph executes the minimum set of recomputations dictated by the dependency topology captured at first read.
The TC39 Proposal: Who Is Behind It and How Far Along
The proposal entered Stage 1 in April 2024 and has since advanced through TC39's staged process toward specification-grade status, with a reference signal-polyfill package shipping TypeScript definitions for early experimentation. Authorship spans engineers from Google's Angular team, Microsoft, and Bloomberg alongside framework authors from the Qwik, Aurelia, Solid, and Svelte communities. The full specification and design space are tracked publicly in the official TC39 Signals proposal repository.
The strategic significance is not performance — it is portability. A language-level reactive core means frameworks could eventually drop their bespoke graph implementations, shrink bundle payloads, and interoperate: shared observable state across micro-frontend boundaries regardless of which framework renders it.
The Performance Mathematics: Push Updates vs. Diffing
Update Path Comparison
- React/Next.js commit path: setState → re-execute component subtree → allocate new virtual DOM nodes → reconcile diff → commit to host DOM. Cost scales with subtree size; the React Compiler mitigates it via automatic memoization, but the fundamental pull-diff-commit pipeline remains.
- Signal commit path: write to Signal.State → mark dependents dirty → re-evaluate only the bound expressions → direct DOM property updates. Cost scales with the number of bindings to that exact state.
Empirically, results on the js-framework-benchmark consistently place signal-driven frameworks such as Solid and Preact-with-signals near vanilla-JS latency for keyed row updates, while React sits materially further back on mutation-heavy workloads. The trade-off is memory: every binding carries subscriber bookkeeping. For dashboards, collaborative editors, tickers, and live-sports UIs, that CPU-for-RAM exchange is a bargain; for a marketing site rendered once, it is dead weight.
Where React's Model Still Wins
- Server-centric architecture: React Server Components, streaming SSR, and Next.js's App Router data flow have no signal equivalent — signals are structurally client-only constructs.
- Concurrent features: transitions, Suspense orchestration, and interruptible rendering depend on re-execution semantics; a synchronous push model integrates awkwardly with interruption guarantees.
- Ecosystem gravity: hiring pool, libraries, tooling, and React DevTools remain unmatched, which compounds for large teams.
React's Official Position: Compiler, Not Signals
React core contributors have been publicly engaged with the proposal's design discussions, but their architectural bet is different: preserve the re-render-everything mental model and let the React Compiler eliminate wasted renders through automatic memoization (a shift we analyzed in depth in our React Compiler production write-up). Signals require developers to reason about subscriptions and identity; React doubles down on values and immutability. Both camps optimize the same bottleneck — redundant re-execution — with opposite philosophies. For teams, this means signals adoption inside React will be an interop story, not a rewrite story, primarily via useSyncExternalStore bridges.
Next.js-Specific Implications
Signals Cannot Cross the RSC Boundary
Server Component payloads serialize plain data. A signal graph cannot be serialized, transferred, and resumed — it must be constructed during hydration inside client components. Passing a signal as a prop from a server component fails at build time in typed setups. Architecturally, this confines signals to client islands: dynamically imported interactive regions embedded in a server-rendered shell.
Practical Interop Today
The most production-proven path is Preact Signals running inside React via @preact/signals-react, which integrates through useSyncExternalStore. The pattern that works in Next.js: a module-scope signal store shared across client islands — no provider hierarchy, no context re-renders, no prop drilling — while the server shell handles routing, streaming, and SEO-critical content. Hot, high-frequency widgets (live cursors, charts, presence indicators) become signal-driven islands; everything else stays in the RSC world.
Adoption Playbook for Engineering Teams
- Profile before migrating: use React Profiler and INP field data to locate components where re-render time dominates interaction latency. Those — and only those — are signal candidates.
- Isolate, don't rewrite: wrap the hot subtree in a client island with @preact/signals-react; keep the parent tree untouched. Measure TTI and INP deltas against the RSC-only baseline.
- Model state granularity deliberately: over-splitting signals creates graph churn; a few well-scoped Signal.State roots feeding Computeds usually outperform dozens of micro-cells.
- Build signal literacy now: prototype against the signal-polyfill so the team understands the semantics before they arrive natively in browsers.
- Track the spec, not the hype: Stage progression dictates ecosystem timing; framework reactivity cores will only begin collapsing once implementations ship.
Strategic Outlook: Two Models, One Stack
The likely end-state is coexistence, not conquest. React and Next.js retain the server-centric, compiler-optimized mainstream while signal islands absorb the update-heavy edges of the UI. The standardization of fine-grained reactivity reduces framework lock-in at exactly the moment Next.js consolidates it — a healthy tension. Teams that learn both models will compose them; teams that treat this as a religious war will mis-architect their next build. If you are weighing how a hybrid RSC-plus-signals architecture fits your product roadmap, explore our edge-optimized frontend engineering services, and for real-world implementations of these patterns, review the work documented on our portfolio of production Next.js builds alongside deeper technical breakdowns on our studio blog.