Introduction to Signals
Learn Signals, Angular's modern, explicit reactivity primitive for holding and reading state.
What Is a Signal?
A signal is a wrapper around a value that notifies anything reading it whenever that value changes. Unlike a plain class property, reading a signal is an explicit function call — signal() — which is what lets Angular track precisely which parts of the UI depend on it.
Reading and Writing a Signal
import { Component, signal } from '@angular/core';
@Component({ selector: 'app-counter', standalone: true, template: ` <button (click)="increment()">Clicked {{ count() }} times</button> `,})export class CounterComponent { count = signal(0);
increment() { this.count.set(this.count() + 1); }}count() reads the current value — count is the signal object itself, not the value. This is the same explicit-call pattern used by other frameworks' fine-grained reactivity systems.
Signals in Templates
A signal is called with () directly in the template too, exactly like in the component class — Angular's template compiler understands this and tracks the dependency automatically.
<p>{{ count() }}</p><p [class.zero]="count() === 0">Status</p>update() vs set()
set() replaces a signal's value entirely; update() derives the new value from the current one, which is often clearer and safer for anything based on the previous state.
count.set(10); // replace entirelycount.update(c => c + 1); // derive from current valueWhy Signals Were Introduced
Classic Angular relies on Zone.js to detect when something might have changed, then re-checks the entire component tree to find what actually did — broad and somewhat wasteful. Signals let Angular know exactly which values changed and exactly which parts of the template depend on them, enabling much more precise, efficient updates.
| Classic (Zone.js) | Signals | |
|---|---|---|
| Change detection | Runs broadly after any async event | Runs precisely, only for affected bindings |
| Reading state | Direct property access | Explicit function call: mySignal() |
| Dependency tracking | Implicit, via Zone.js patching | Explicit, tracked per-signal |
Common Beginner Mistakes
{{ count }} in a template renders the signal object's description, not its value — you need {{ count() }}.
A signal's value is only changed through .set() or .update() — direct assignment replaces the signal itself, which is almost never what you want.
FAQs
No — classic property-based reactivity and signals interoperate, and you can adopt signals incrementally in new or refactored code.
Conceptually, yes — all three wrap a value so a framework can track reads and react to writes, though the exact syntax and semantics differ.
Summary
Signals give Angular explicit, fine-grained reactivity — read with (), written with .set()/.update(). Next, you'll learn computed() and effect(), the two companion primitives that build on signals.