Skip to content

subscribe()

The subscribe() function calls a callback when source dependencies change. Unlike effect(), it separates the tracked source from the untracked callback.

const unsubscribe = subscribe(source, callback)

source : A function that reads signals. These reads are tracked as dependencies.

callback : A function called with the source’s return value. Signal reads here are not tracked.

An unsubscribe function that stops the subscription.

The source function determines dependencies; the callback can read any signals without creating subscriptions:

const count = signal(0);
const multiplier = signal(2);
subscribe(
() => count(), // tracked
(value) => console.log(value * multiplier()) // NOT tracked
);
count(5); // logs: 10
multiplier(3); // no log — multiplier isn't a dependency
count(6); // logs: 18

Like effects, subscribe() calls the callback immediately with the initial value:

const count = signal(0);
subscribe(
() => count(),
(value) => console.log('Count:', value)
);
// logs: "Count: 0"
count(1);
// logs: "Count: 1"

Call the returned function to stop the subscription:

const unsubscribe = subscribe(
() => count(),
(value) => console.log(value)
);
count(1); // logs: 1
unsubscribe();
count(2); // nothing

Sync to an external system only when specific signals change:

const userId = signal('user-1');
const settings = signal({ theme: 'dark' });
// Only re-sync when userId changes, not settings
subscribe(
() => userId(),
(id) => {
externalSystem.setUser(id);
externalSystem.applySettings(settings()); // read but not tracked
}
);
const query = signal('');
const config = signal({ limit: 10 });
subscribe(
() => query(),
(q) => {
// config changes don't trigger new searches
fetch(`/search?q=${q}&limit=${config().limit}`);
}
);

The source can be any reactive expression:

const items = signal([1, 2, 3]);
const filter = signal('all');
subscribe(
() => {
// Both items and filter are dependencies
const all = items();
return filter() === 'all' ? all : all.filter(x => x > 2);
},
(filtered) => {
renderList(filtered);
}
);
  • effect() — Simpler API when you want all reads tracked
  • computed() — For derived values, not side effects