Fragment cache (ISR boundary)
The outer page is dynamic — every request re-renders. The inner subtree is wrapped in <ISR ttl={10}> and is served from cache for 10 seconds. Refresh quickly: the outer timestamp ticks, the inner one stays frozen until the TTL expires and the next render re-stores it.
Output
Outer (live): 2026-06-15T18:00:14.656Z
How it works
The page renders normally; when the JSX runtime hits the <ISR> boundary it calls a host bridge __bextIsrFragmentLookup. On hit it returns the cached HTML and the function child is skipped. On miss the function runs, the result is stored via __bextIsrFragmentStore, and the HTML is yielded back into the parent stream.
Cache lives in bext_core::cache::fragment::FragmentCache — the same store the layout cache uses, with a separate TTL-aware map. Storage is in-process today; disk-backing + cross-process coherence is the next iteration.
import { ISR } from "@bext-stack/framework/cache";
// The outer page is dynamic — re-renders on every request.
// The inner subtree is cached for 10 s via <ISR ttl={10}>.
// Refresh quickly and the inner timestamp stays frozen; the outer
// timestamp ticks per request.
export default function Page() {
const outer = new Date().toISOString();
return (
<div>
<p>Outer (live): {outer}</p>
<ISR cacheKey="featured" ttl={10}>
{async () => {
// Simulate slow data — this only runs on cache miss.
await new Promise(r => setTimeout(r, 50));
const inner = new Date().toISOString();
return `<p style="background:#eef;padding:.5rem">Inner (cached 10s): ${inner}</p>`;
}}
</ISR>
</div>
);
}