Building a Dashboard with Charts
Aggregate your storage data, render it live on a page, and keep it fast — the dashboard pattern end to end.
A dashboard is a page backed by a few well-chosen queries: counts, sums, recent items, and grouped stats. This tutorial assembles one — data first, then rendering, then keeping it fast.
Step 1 — Get the Data
Dashboards read, never write. Build a function per metric (or one function returning an object with all of them):
- Counts —
function_searchwith thehitsout-pin (total matching documents), one per filtered query: open tasks, shipped orders, this week's signups. - Recent items —
function_search+query_sort_fieldon_meta.createddescending +limit10 — see search tips. - Grouped stats — aggregations where the storage supports them; for anything heavy, precompute counters on write instead (see performance below).
Return everything from one function as an object built with object_new_fields — one call, one payload for the page.
Step 2 — Render the Page
- A
state_pagefor the dashboard URL, scoped for your team (*loggedinor a custom scope). - On load, run the metrics function from the render flow and pass results into state elements: number tiles (styled elements), a recent-items list (iterate the array), and your chart component.
- For real charts, mount a custom React component in the page and feed it the metrics object — see Components and RUAL Library for passing data to components.
- Want it live? Real-time search updates the metrics as documents change — worth it on shared boards, overkill on quiet data (see real-time vs polling).
Step 3 — Keep It Fast
- Cache the metrics function with a
cache_keyonfunction_searchand a short TTL via Redis — the dashboard loads instantly even with thousands of documents. See caching patterns. - Precompute counters on write — increment a stats document on each create (
mutations_increment_by_field) instead of counting at read time; reads become a singlefunction_get_document. - Avoid dashboard-side loops — if the page needs per-item computation, do it in the function with
array_map, not in the render. - Watch out for the aggregation traps in Common Pitfalls.
- One metrics function returning one object.
- Sort + limit on every "recent" list.
- Cache key on expensive searches; counters for hot stats.
- Scope set intentionally (no accidental
*publicdashboards).
