In plain words

A signal is a value that knows who is using it. You read it, you write it, and anything that depended on its old value updates itself. Change a count signal and only the parts of the screen that actually read count change. The rest of the component is left untouched.

This is the frontend-reactivity meaning of the word, the one used by Solid, Angular, Preact, Qwik, and Vue. It has nothing to do with Unix process signals like SIGTERM or the Signal messaging app. Same word, unrelated worlds.

How it works

Signals come as a trio. The names differ by framework, but the roles are the same:

  • Signal - a writable value you can read and set. Solid's createSignal, Angular's signal, Preact's signal.
  • Computed (also called a memo or derived) - a read-only value calculated from other signals and cached until one of them changes.
  • Effect - runs a side effect, such as updating the DOM or logging, whenever a signal it reads changes.

What wires them together is automatic dependency tracking. When a computed or effect reads a signal, it quietly subscribes to it. When you write that signal, the runtime notifies exactly those subscribers. There are no dependency arrays to maintain and no manual subscriptions:

import { signal, computed } from "@angular/core";

const count = signal(0);                          // a writable signal
const doubleCount = computed(() => count() * 2);  // a derived (computed) signal

Write count.set(1) and doubleCount is marked stale, then recomputed the next time something reads it. An effect that reads doubleCount re-runs. Nothing else is touched. That targeting is what "fine-grained" means, and it skips the virtual-DOM diffing that re-renders and reconciles whole component trees.

Why it matters

The performance model is the whole point. React's default is to re-run a component on every state change, build a fresh virtual DOM tree, diff it against the last one, and patch the difference. With signals a component body often runs once; after that, writes flow straight to the specific computations and DOM nodes that read the changed value. The result is targeted updates and predictable cost, which is why signals are central to frameworks like Qwik and to the broader shift away from virtual-DOM reconciliation.

React declined on purpose. As core team member Andrew Clark put it, "We might add a signals-like primitive to React but I don't think it's a great way to write UI code. It's great for performance. But I prefer React's model where you pretend the whole thing is recreated every time." React's bet is to recover the performance with a compiler instead of changing how you write components. Signals pair naturally with islands architecture, where small interactive regions hydrate independently.

Origin

The reactive-primitive idea goes back to Knockout's observables in 2010, with MobX adding glitch-free push-pull propagation in 2015. The term "signal" as frameworks use it today traces to the S.js library in 2013, and the modern resurgence, along with the "fine-grained reactivity" framing, came from SolidJS and Ryan Carniato.

There is now a TC39 proposal to add signals to JavaScript itself, at Stage 1 since April 2024. Its goal is to give every framework one shared primitive so models and libraries can move between them. It is still early, in a deliberate prototyping phase before advancing, so for now each framework ships its own implementation.

Common confusions

Confused withHow it differs from a signal
React useStateuseState makes React re-render the component and reconcile a new virtual DOM tree on each change. A signal updates only the computations and nodes that read it. Using useState is not using a signal.
Vue refEffectively the same primitive. Vue's own docs call signals "the same kind of reactivity primitive as Vue refs." The difference is API ergonomics: a ref's .value versus a getter/setter pair.
MobX observableThe direct ancestor. Signals are essentially the same observable-graph, auto-tracking idea, repackaged as a smaller standalone primitive.
Unix / POSIX signalAn operating-system notification sent to a process, like SIGINT or SIGTERM. Same word, completely unrelated to UI reactivity.