Solara caching and memoization — use_memo hook vs @solara.memoize decorator vs solara.cache.storage, with decision guide
| Mechanism | Scope | Works outside components? | Multi-value cache? |
|---|---|---|---|
| use_memo | Per-component instance | No (hook) | No — one cached value |
| @solara.memoize | Global (all callers) | Yes | Yes — keyed by arguments |
| solara.cache.storage | Global (manual) | Yes | Yes — dict-like LRU |
| solara.computed | Reactive graph | Yes | No — single derived value |
Caches a function's return value within a single component instance. Re-computes only when dependencies change:
@solara.component
def StatsView(data: list):
stats = solara.use_memo(lambda: compute_expensive_stats(data),
dependencies=[data])
solara.Text(f"Mean: {stats['mean']:.2f}")
dependencies=[data] — recompute when data changes.dependencies=[] — compute once, never recompute.dependencies=None — auto-detect from nonlocal variables (default).Gotcha — objects without equality comparison cause infinite re-renders:
# BAD — dict/object created each render, always "new", triggers recompute loop
@solara.component
def Bad():
config = {"key": "value"}
result = solara.use_memo(lambda: process(config), dependencies=[config])
# GOOD — wrap creation in use_memo too
@solara.component
def Good():
config = solara.use_memo(lambda: {"key": "value"})
result = solara.use_memo(lambda: process(config), dependencies=[config])
Global function-level cache. Caches multiple return values keyed by arguments. Works anywhere — not just in components:
@solara.memoize
def load_dataset(path: str) -> pd.DataFrame:
return pd.read_csv(path)
DataFrames, dicts, and other unhashable types need a key function:
@solara.memoize(key=lambda df, column: (id(df), column))
def column_mean(df: pd.DataFrame, column: str) -> float:
return df[column].mean()
Control cache size or backend:
import cachetools
@solara.memoize(storage=cachetools.LRUCache(maxsize=50))
def expensive(x: int) -> int:
return x ** 2
@solara.memoize exposes a .use_thread attribute for automatic background execution with caching — cached values return immediately, uncached values compute in a thread:
@solara.memoize
def slow_compute(x):
time.sleep(2)
return x * 10
@solara.component
def Page():
result = slow_compute.use_thread(42)
solara.ProgressLinear(result.pending)
if result.finished:
solara.Text(f"Result: {result.value}")
Nonlocal variables are not included in the cache key by default. If your function captures nonlocals, either add them as explicit arguments or pass allow_nonlocals=True:
# BAD — multiplier is a nonlocal, not part of cache key
multiplier = 2
@solara.memoize
def scale(x):
return x * multiplier # ValueError: nonlocal detected
# GOOD — make it an argument
@solara.memoize
def scale(x, multiplier):
return x * multiplier
Reactive derived values that auto-update when their reactive dependencies change:
count = solara.reactive(5)
doubled = solara.computed(lambda: count.value * 2)
@solara.component
def Page():
solara.Text(f"Doubled: {doubled.value}") # auto-updates when count changes
Low-level global LRU cache (default 128 items). Used internally by @solara.memoize:
solara.cache.storage["my-key"] = expensive_result
result = solara.cache.storage.get("my-key")
Configure via environment variables:
SOLARA_CACHE=memory (default)SOLARA_CACHE_MEMORY_MAX_ITEMS=128 (default)Enterprise options: memory-size, disk, redis, multi-level.
| Avoid | Do Instead |
|---|---|
| use_memo with unhashable dependencies | Wrap creation in a separate use_memo |
| @solara.memoize with captured nonlocals | Pass them as explicit arguments |
| Unbounded solara.cache.storage = {} | Use solara.cache.Memory(maxsize=N) |
| use_memo outside a component | Use @solara.memoize instead |
| Re-implementing caching with dicts | Use @solara.memoize with custom storage |
Load this skill when implementing caching, memoization, or expensive computations in a Solara application.
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer