Documentation
Docs
Introduction
Getting Started
Tutorial: build an app
Core Concepts
Routing
Server-Side Rendering
Mimir, state management
Pages & Layouts
API Routes
Styling & Theming
Building & Deploying
API Reference
Guides
Recipes
FAQ (use cases)
Recipe , data fetching
Where you fetch data depends on whether it should be in the server-rendered HTML (for first paint and SEO) or loaded after hydration (for per-user or frequently-changing data). rune supports both.
Option A , data available at render (best first paint)
If the data is available on the server (a module import, a database the server can read, a value computed at startup), render with it directly, no fetch needed. The list is in the HTML and indexable.
For a known set, register one cached static route per item so each is fully rendered (see
Programmatic routes). For an embedded dataset (like these docs),
import a generated *.data.ts and render from memory, navigation is instant, no network.
Option B , seed via ssr().__atoms
Compute data on the server and seed it into an atom so the first client render already has it (and components reading the atom update together):
On a cached static page, only seed non-personal data (the HTML is shared). For per-user data, use option C. See Mimir → SSR & hydration.
Option C , fetch after hydration (per-user / live data)
For data that is per-user or changes often, fetch from a same-process API route after mount and store it in an atom:
Storing in an atom (not local state) means the data survives navigation, navigate away and back and it is still there, no refetch.
The API side
Same process, so the API reads the same data the pages render from, no second service, no CORS.
Caching and revalidation
- Page-level: static SSR pages are cached; bust them when underlying data changes with
app.invalidate("/posts") or a tag. See Caching & invalidation.
- Client-level: keep fetched data in atoms; refetch on an interval or on a user action, and update the
atom. The atom is your client cache.
Choosing
| Data | Approach |
|---|---|
| Static/known, want SEO + instant nav | render from a module / embedded data (A) |
| Server-known, page-specific | seed via ssr().__atoms (B) |
| Per-user or live | fetch after hydration into an atom (C) |
| Mutates at runtime, cached pages | API mutation + app.invalidate |
Most apps mix these: marketing/docs use A, a dashboard's shell uses A/B and its live widgets use C.