Cache Derived State in SolidJS with createMemo
Avoid redundant recalculations in SolidJS by memoizing expensive derived signals with createMemo.
12 Nov 2025, 12:13 UTC

The problem: derived work running more often than needed
Imagine a SolidJS component that filters a long list of items every time a search input changes. The filtered array is a derivation: it depends on the raw list and the search query. If you compute that array directly in the component body, SolidJS may recompute it on reads that have nothing to do with its inputs. Fine-grained reactivity means only the parts of the UI that subscribe to a signal should update, but an uncached derivation runs each time something reads it.
Useful takeaway: wrap expensive derivations in createMemo so SolidJS caches the result and recomputes only when a tracked reactive dependency changes.
What createMemo actually does
createMemo wraps a derivation function and returns a read-only signal. The first time the memo is read inside a tracking context—such as a component template or an effect—it runs the function, records every signal it touches, and stores the result. Later reads return the cached value until one of those tracked signals changes.
This differs from createEffect, which runs for side effects and returns nothing. A memo must be pure: no DOM writes, no analytics calls, and no variable mutations. It also differs from a plain getter because it does not re-run on unrelated reads.
Assumption: this behavior applies to SolidJS 1.x. Check your installed version before relying on it, since pre-1.0 APIs may differ.
Worked example: memoizing a filtered list
Here is a component with a counter that updates frequently and a filtered list derived from a search query. The memo should recompute only when the list or query changes, not when the counter ticks.
import { createSignal, createMemo, For } from "solid-js";
function List() {
const [items, setItems] = createSignal([
{ id: 1, name: "Apple" },
{ id: 2, name: "Banana" },
{ id: 3, name: "Cherry" },
]);
const [query, setQuery] = createSignal("");
const [tick, setTick] = createSignal(0);
const filtered = createMemo(() => {
console.log("recomputing filtered list");
return items().filter((item) =>
item.name.toLowerCase().includes(query().toLowerCase())
);
});
setInterval(() => setTick((t) => t + 1), 1000);
return (
setQuery(e.currentTarget.value)}
placeholder="Search"
/>
Tick: {tick()}
{(item) => {item.name}}
);
}
Run this in a SolidJS project created with Vite or another supported bundler. Open your browser console, type in the search box, and watch for the log. You should see "recomputing filtered list" when the query changes, but not on every one-second tick. That confirms the memo is tracking only items and query.
Risk: if you return a new object or array from the memo on every run, downstream consumers comparing by reference will see a new value each time. SolidJS compares memo outputs by reference, not deep equality, so a fresh array reference can defeat the cache for consumers.
When not to use createMemo
- Trivial math or string concatenation: the subscription tracking can cost more than the computation.
- Side effects: DOM updates, analytics calls, or mutating outside variables belong in
createEffector event handlers. - Execution order dependencies: do not assume one memo runs before another.
If you are unsure whether a derivation is expensive enough, profile the component first. Add the memo only if measurements show the derivation is a bottleneck.
Practical verification
- Create a counter signal and a memo that doubles its value.
- Place a
console.loginside the memo function. - Read the memo in the template and read the counter in an unrelated sibling element.
- Update the counter and confirm the log fires only when the counter changes, not when other signals are read.
Build the app and use browser dev tools to confirm that components consuming only the memoized value update while siblings reading other signals do not re-render. This is a static code review and runtime observation step; no command output is guaranteed.
Closing
Use createMemo when a derived value is expensive to compute and its inputs change independently of its consumers. Keep the function pure, watch out for reference equality, and verify with browser dev tools before adopting it broadly.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.