NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
npm · #4327 most downloaded on npm
Manage state with style in every framework
Last release 3 months ago
07 Jul 2026
Ships unpredictably
gaps range from 2 weeks to 10 months
Nearly every release is documented
notes for 33 of 33 stable releases
Nothing withdrawn
no release was ever pulled
4 years old
33 releases · first in 2022
One column per quarter.
Reconciling a reverted batch write used to roll the signal's version number back, breaking version monotonicity. A lazy computed that read the signal
#947 2910fbf Thanks @JoviDeCroock! - Fix computeds returning stale values after a batch reverts a signal to its original value.
Reconciling a reverted batch write used to roll the signal's version number back, breaking version monotonicity. A lazy computed that read the signal during the batch had already observed the intermediate version, so a later write could re-mint that same version number for a different value and the computed would treat it as unchanged forever. Subscriber nodes that saw the pre-batch version are now fast-forwarded instead, keeping the no-op skip optimization without ever reusing version numbers.
#945 d40746b Thanks @andrewiggins! - Prevent model effect capture while creating effects inside untracked() and action() callbacks.
If you create an effect() inside an untracked() callback within a createModel() factory, that effect is no longer disposed when the model is disposed. Use the disposer returned by effect() to clean it up manually.
### Patch Changes - #937 `beb84c1` Thanks @JoviDeCroock! - Optimize bundle size
beb84c1 Thanks @JoviDeCroock! - Optimize bundle size### Patch Changes - #915 `054afc1` Thanks @JoviDeCroock! - Shave some bytes by using untracked to implement peek
054afc1 Thanks @JoviDeCroock! - Shave some bytes by using untracked to implement peek### Patch Changes - #906 `0c65390` Thanks @JoviDeCroock! - Wrap nested object methods returned from createModel so composed models keep action batchin
#906 0c65390 Thanks @JoviDeCroock! - Wrap nested object methods returned from createModel so composed models keep action batching semantics without manual action wrappers.
#911 6c17923 Thanks @JoviDeCroock! - Avoid hard-requiring ESNext.Disposable in consumer tsconfigs for Model and effect() types.
### Minor Changes - #891 `308c921` Thanks @JoviDeCroock! - Prevent batches where a signal goes from A --> B --> A from triggering dependent updates, a
308c921 Thanks @JoviDeCroock! - Prevent batches where a signal goes from A --> B --> A from triggering dependent updates, a computed/effect should not re-run when the dependencies in a batched update amount to an equal value.`createModel` provides a structured way to create reactive model classes that encapsulate signals, computed values, and actions:
#812 19ac39b Thanks @andrewiggins! - Add createModel and action to signals core package
createModel provides a structured way to create reactive model classes that encapsulate signals, computed values, and actions:
const CounterModel = createModel((initialCount = 0) => {
const count = signal(initialCount);
const doubled = computed(() => count.value * 2);
effect(() => {
console.log("Count changed:", count.value);
});
return {
count,
doubled,
increment() {
count.value++;
},
};
});
const counter = new CounterModel(5);
counter.increment(); // Updates are automatically batched
counter[Symbol.dispose](); // Cleans up all effects
Key features:
Symbol.disposeaction is a helper that wraps a function to run batched and untracked:
const updateAll = action(items => {
items.forEach(item => item.value++);
}); // All updates batched into single notification
### Patch Changes - #827 `f17889b` Thanks @JoviDeCroock! - Add mangle entry for \_debugCallback
f17889b Thanks @JoviDeCroock! - Add mangle entry for _debugCallback### Patch Changes - #747 `57bc903` Thanks @JoviDeCroock! - Remove internal annotation as it confused TS
57bc903 Thanks @JoviDeCroock! - Remove internal annotation as it confused TS### Minor Changes - #681 `6cc7005` Thanks @JoviDeCroock! - Allow for naming your singals/computeds/effects
6cc7005 Thanks @JoviDeCroock! - Allow for naming your singals/computeds/effectsThis allows effect()'s to be disposed with the new using keyword from the explicit resource management proposal.
#706 4045d2d Thanks @marvinhagemeister! - feat: support disposing effect() with resource management
This allows effect()'s to be disposed with the new using keyword from the explicit resource management proposal.
Whenever an effect goes out of scope the Symbol.dispose function is called automatically.
const count = signal(0);
function doSomething() {
// The `using` keyword calls dispose at the end of
// this function scope
using _ = effect(() => {
console.log(count.value);
return () => console.log("disposed");
});
console.log("hey");
}
doSomething();
// Logs:
// 0
// hey
// disposed
### Minor Changes - #697 `5e7a167` Thanks @JoviDeCroock! - Publicly expose dispose() on an effect callback
5e7a167 Thanks @JoviDeCroock! - Publicly expose dispose() on an effect callback### Minor Changes - #634 `62bed44` Thanks @JoviDeCroock! - Add an option to specify a watched/unwatched callback to a signal ### Patch Changes - #688
62bed44 Thanks @JoviDeCroock! - Add an option to specify a watched/unwatched callback to a signal587e702 Thanks @JoviDeCroock! - Loosen up types for watched and unwatched`js const sig: Signal = useComputed(() => x); `
#587 cd9efbb Thanks @JoviDeCroock! - Adjust the ReadOnlySignal type to not inherit from Signal
this way the type can't be widened without noticing, i.e. when
we'd have
const sig: Signal = useComputed(() => x);
We would have widened the type to be mutable again, which for a computed is not allowed. We want to provide the tools to our users to avoid these footguns hence we are correcting this type in a minor version.
### Minor Changes - #578 `931404e` Thanks @JoviDeCroock! - Allow for passing no argument to the signal and the type to be automatically inferred as T
931404e Thanks @JoviDeCroock! - Allow for passing no argument to the signal and the type to be automatically inferred as T | undefined### Patch Changes - #558 `c8c95ac` Thanks @jviide! - Restore stricter effect callback & cleanup function types
### Minor Changes - #525 `cb6bdab` Thanks @jviide! - Allow setting a signal value inside a computed ### Patch Changes - #535 `58befba` Thanks @jviide!
## 1.5.1 ### Patch Changes - #451 `990f1eb` Thanks @dcporter! - Removes backward-incompatible type export from signals core.
### Minor Changes - #964 `8d5adb1` Thanks @JoviDeCroock! - Add Performance Insights for instance-level update hotspots and explicitly instrumented no-
8d5adb1 Thanks @JoviDeCroock! - Add Performance Insights for instance-level update hotspots and explicitly instrumented no-output-change computed recomputations.9355d96 Thanks @JoviDeCroock! - Add unique identifier to every Signal, this will be present on the brand property of a Signal coming from either signal() or computed()### Minor Changes - #866 `00ba858` Thanks @JoviDeCroock! - Add special case in devtools-ui for component updates - #851 `a7f500b` Thanks @JoviDeCroock
#866 00ba858 Thanks @JoviDeCroock! - Add special case in devtools-ui for component updates
#851 a7f500b Thanks @JoviDeCroock! - Add special copy for component renders
256a331 Thanks @XantreGodlike! - Add untracked function, this allows more granular control within effect/computed around what should affect re-runs.### Patch Changes - #620 `4cda002` Thanks @developit! - Simplify text update patch to avoid using new internals - #618 `021c726` Thanks @JoviDeCroock!
#620 4cda002 Thanks @developit! - Simplify text update patch to avoid using new internals
#618 021c726 Thanks @JoviDeCroock! - Ensure that the Effects versions are updated when using it as a JSX Signal
8c12a0d Thanks @rschristian! - Removes package.json#exports.umd, which had invalid paths if they were ever to be consumed26f6526 Thanks @andrewiggins! - Change effect callback return type from void to unknown. Same for effect cleanup function.Updated dependencies \[`931404e`]:
931404e Thanks @JoviDeCroock! - Allow for passing no argument to the signal and the type to be automatically inferred as T | undefined931404e]:
8b70764 Thanks @JoviDeCroock! - Support toJSON on a Signal8e726ed Thanks @billybimbob! - Add typing for effect cleanupUpdated dependencies \[`d846def`, `cb6bdab`, `d846def`, `d846def`, `d846def`]:
## 1.2.2 ### Patch Changes - #415 `79efe32` Thanks @prinsss! - Fix error when using useSignal with UMD builds of @preact/signals.
`54094d5` Thanks @JoviDeCroock! - Format react/preact components in the debug logging
54094d5 Thanks @JoviDeCroock! - Format react/preact components in the debug logging https://github.com/preactjs/signals/pull/84424fa9f7 Thanks @rschristian! - Fixes UMD builds of @preact/signals and @preact/signals-react#205 4b73164 Thanks @jviide! - Use the same tracking logic for both effects and computeds. This ensures that effects are only called whenever any of their dependencies changes. If they all stay the same, then the effect will not be invoked.
#207 57fd2e7 Thanks @jviide! - Fix effect disposal when cleanup throws
#209 49756ae Thanks @jviide! - Optimize dependency value change checks by allowing earlier exists from the loop
## 1.2.0 ### Minor Changes - #387 `6e4dab4` Thanks @XantreGodlike! - Removed difference in behaviour between adapters, signals that use a JSX value wi
6e4dab4 Thanks @XantreGodlike! - Removed difference in behaviour between adapters, signals that use a JSX value will correctly re-render the whole component rather than attempting the JSX-Text optimization.This release improves performance of signals across all measurements. We want to especially highlight @jviide 's work in #161 here as it did outstanding strides on reducing memory usage, improving performance and ending up making signals one (if not the) fastest reactive library at the time of this writing 🎉
#183 79ff1e7 Thanks @jviide! - Add ability to run custom cleanup logic when an effect is disposed.
effect(() => {
console.log("This runs whenever a dependency changes");
return () => {
console.log("This runs when the effect is disposed");
});
});
#170 3e31aab Thanks @jviide! - Allow disposing a currently running effect
#188 b4611cc Thanks @jviide! - Fix .subscribe() unexpectedly tracking signal access
#162 9802da5 Thanks @developit! - Add support for Signal.prototype.valueOf
#161 6ac6923 Thanks @jviide! - Remove all usages of Set, Map and other allocation heavy objects in signals-core. This substaintially increases performance across all measurements.
### Patch Changes - #215 `515ff33` Thanks @jmeistrich ! - Fix signal not updated in React production build
515ff33 Thanks @jmeistrich ! - Fix signal not updated in React production build3db7500 Thanks @JoviDeCroock! - Fix server-sider-render error when unmounting a signal passed as text into JSX.#143 f2ba3d6 Thanks @Pauan! - Simplify batch() to use a single flag instead of a counter
#150 160ea77 Thanks @marvinhagemeister! - Fix computed signal being re-calculated despite dependencies not having changed
#137 4385ea8 Thanks @jviide! - Fix .subscribe's TypeScript type
#148 b948745 Thanks @marvinhagemeister! - Move types field in package.json to the top of the entry list to ensure that TypeScript always finds it.
#149 00a59c6 Thanks @marvinhagemeister! - Fix invalidated signals inside batch() not being refreshed when read inside a batching operation. This fixes a regression.
### Minor Changes - #91 `fb74bb9` Thanks @JoviDeCroock! - add the useSignalEffect hook ### Patch Changes - #186 `7242bd6` Thanks @marvinhagemeister! -
fb74bb9 Thanks @JoviDeCroock! - add useSignalEffect hook.subscribe()-method to signals to add support for natively using signals with Svelte - #134 @marvinhagemeisterSignal class name - #100 @marvinhagemeister.subscribe()-method to signals to add support for natively using signals with SvelteSignal class name### Patch Changes - #761 `c7c3218` Thanks @JoviDeCroock! - Fix reporting complex values to the extension
c7c3218 Thanks @JoviDeCroock! - Fix reporting complex values to the extension.peek() when called on a deactivated signal.Updated dependencies \[`6cc7005`]:
#681 6cc7005 Thanks @JoviDeCroock! - Initial release of @preact/signals-debug
#727 8fe8dec Thanks @JoviDeCroock! - Add devtools capabilities and component tracking
6cc7005]:
.peek() method to read from signals without subscribing to them.702a9c5: Update TypeScript types to mark computed signals as readonly
4123d60: Fix TypeScript definitions not found in core
1e4dac5: Add prepublishOnly scripts to ensure we're publishing fresh packages
prepublishOnly scripts to ensure we're publishing fresh packages## 0.0.2 ### Patch Changes - #401 `17e1491` Thanks @andrewiggins! - Lower required babel version required as a peer dependency
17e1491 Thanks @andrewiggins! - Lower required babel version required as a peer dependencyYour coding agent can read these notes before it upgrades. Set up the MCP server →