Hi folks 👋 I've been using OpenUI for a while now and it's genuinely great, but there's one gap that hurts the UX of everything we build with it: there's no caching between Query() and our tools, so users see loading placeholders every single time they navigate away and come back to a page, even when we fetched that exact data seconds ago.
What I'd love to see is TanStack Query style caching with stale-while-revalidate as the default behavior: when a user returns to a page, render the cached result instantly, then re-fetch in the background and update in place. No spinner, no default-value placeholder flash, and the data still ends up fresh.
The existing pieces are a solid foundation. Reactive $variable changes re-fetch dependent queries, the optional refresh-interval argument covers polling, and @Run gives manual control. What's missing is the cache layer itself:
- Stale-while-revalidate rendering: serve the last known result for a given tool + args immediately, revalidate in the background. This is the big one for us.
- Stale-time / cache-time control: let us say how long a result is considered fresh, so repeat visits within that window don't hit the backend at all.
- Request deduplication: multiple components querying the same tool with the same args should share one in-flight request.
- Declarative invalidation: today the post-mutation pattern is
@Run(createResult), @Run(tickets), which means the LLM has to know every query a mutation affects. Tag-based invalidation (mutation invalidates "tickets", every query tagged "tickets" refetches) would be more robust to generation errors.
- Cache persistence: opt-in persistence to
localStorage/IndexedDB, so even a full reload or a returning session starts from cached data instead of spinners.
- (Stretch) Retry with backoff and optimistic updates on mutations.
Since OpenUI already separates generation from execution, this fits naturally in the runtime/toolProvider layer: zero new tokens from the model, and it could even ship as a toolProvider middleware without touching OpenUI Lang itself.
With this, Queries and Mutations in OpenUI would honestly be a killer feature. I'm very open to contributing the implementation if the maintainers can weigh in on the preferred design (runtime-level cache vs. toolProvider middleware). Thank you!
Hi folks 👋 I've been using OpenUI for a while now and it's genuinely great, but there's one gap that hurts the UX of everything we build with it: there's no caching between
Query()and our tools, so users see loading placeholders every single time they navigate away and come back to a page, even when we fetched that exact data seconds ago.What I'd love to see is TanStack Query style caching with stale-while-revalidate as the default behavior: when a user returns to a page, render the cached result instantly, then re-fetch in the background and update in place. No spinner, no default-value placeholder flash, and the data still ends up fresh.
The existing pieces are a solid foundation. Reactive
$variablechanges re-fetch dependent queries, the optional refresh-interval argument covers polling, and@Rungives manual control. What's missing is the cache layer itself:@Run(createResult), @Run(tickets), which means the LLM has to know every query a mutation affects. Tag-based invalidation (mutation invalidates"tickets", every query tagged"tickets"refetches) would be more robust to generation errors.localStorage/IndexedDB, so even a full reload or a returning session starts from cached data instead of spinners.Since OpenUI already separates generation from execution, this fits naturally in the runtime/
toolProviderlayer: zero new tokens from the model, and it could even ship as atoolProvidermiddleware without touching OpenUI Lang itself.With this, Queries and Mutations in OpenUI would honestly be a killer feature. I'm very open to contributing the implementation if the maintainers can weigh in on the preferred design (runtime-level cache vs.
toolProvidermiddleware). Thank you!