Fresh Data at Scale
By Syncfusion®, Inc. · Last updated
Why one fresh part slows a whole page, server islands with server:defer, fallback content, encrypted props and cookies in server islands, Cache-Control and CDN caching, live collections with defineLiveCollection(), getLiveCollection() and getLiveEntry(), and error handling.
Fresh Data at Scale
- Some parts of a page change every second: stock left, prices, "Hello, Asha".
- If one small part is personal or slow, the whole page must wait for it, and cannot be cached.
Astro has two tools for this:
- Server islands render that one part later, on the server, while the rest of the page is fast and cacheable.
- Live collections load fresh data on every request, with the same style as content collections.
- In this lesson, you will also tell browsers and CDNs how long to keep a page with cache headers.
Simple lesson: keep most of the page fast and cached, and load only the fresh part on each request.
A Real-World Example
- Asha opens a small shop page in her journal.
- The product text is the same for everyone. It can be built once.
- The "Only 3 left" number changes all the time.
- She wraps the stock box in a server island. The page loads at once with "Checking stock…", then the real number appears.
Press ▶ Run. The page shows the fallback first. A moment later, the Terminal shows the island's own request, and the stock appears.
What happened:
- The page itself is static: it was built ahead of time (
▶ /in the Terminal). server:deferleft a placeholder with the fallback content.- The browser then asked the server for the island alone (
/_server-islands/StockLeft). - The server rendered
StockLeftfresh and the browser swapped it in.
What You Will Learn
In this lesson, you will learn:
- Why one fresh part can slow down a whole page.
- How to make a server island with
server:defer. - How to show a fallback while it loads.
- How props and cookies work inside server islands.
- How to cache pages with
Cache-Controlheaders. - How to load fresh data with live collections.
- How to handle live collection errors.
Server Islands
The Problem They Solve
Animation: the static page arrives at once from the cache with a grey placeholder. A second, smaller request then fills the placeholder with fresh stock data.
Page (cached, instant)
Product text
Checking stock…
Only 3 left!
Server /_server-islands/StockLeft
The page comes first. The island follows with its own small request.
- Without islands, a personal or slow part makes the whole page on-demand.
- On-demand pages are slower and harder to cache.
- With a server island, the page can stay static or cached. Only the island runs on every request.
- Server islands are not client islands. They run on the server and send no JavaScript framework. Only a tiny script fetches their HTML.
Making a Server Island
- Write a normal
.astrocomponent. - Add
server:deferwhere you use it:<StockLeft server:defer />. - Add an adapter. Server islands are rendered on demand, so the site needs a server.
- The page around the island can still be prerendered (static).
- Many server islands on one page load in parallel.
Showing a Fallback
- Put content in
slot="fallback"to show it while the island loads. - A good fallback has the same size as the result, so the page does not jump.
- Common fallbacks: "Loading…", a grey box, a generic avatar.
Server islands need an adapter, such as @astrojs/node, Netlify, Vercel or Cloudflare. Without one, Astro stops with an error.
Simple lesson: server:defer renders a component later, on the server, with a fallback until then.
Props and Personal Data in Server Islands
Passing Props
- You can pass props:
<StockLeft id="mug" server:defer />. - Astro encrypts the props and puts them in the island's URL, so visitors cannot read or change them.
- Props must be data: text, numbers, arrays, plain objects. No functions.
- Keep props small. Big props make the URL long (Astro switches to a POST request if it gets too long).
Press ▶ Run. Three islands share one component, each with its own id prop. They load in parallel.
- [JS] Leave out
interface Props.
Cookies and Personal Content
- A server island gets the visitor's request, cookies included.
- So a static, cached page can still say "Hello, Asha" in its header.
- Inside the island,
Astro.urlis the island's own address. To know which page it is on, readAstro.request.headers.get("Referer").
Press ▶ Run. The home page says "Hello, guest". Click Log in as Asha. Back on the same static page, the island now greets Asha.
- [JS] In
login.js, leave outimport typeand: APIRoute.
Do not put personal data in a page that a CDN caches for everyone. Put it in a server island, so only the island is personal.
Simple lesson: server islands get props (encrypted) and the visitor's cookies, so cached pages can show personal parts.
Caching Pages
Cache-Control Headers
- A cache keeps a copy of a response, so the next visitor gets it without running your code.
- Browsers cache. CDNs (servers near your visitors) cache too.
- An on-demand page sets how long with the
Cache-Controlheader:
| Header value | Meaning |
|---|---|
public, max-age=60 | Anyone may keep it for 60 seconds |
private, no-store | Never cache (personal pages) |
public, s-maxage=600 | CDNs keep it 10 minutes, browsers follow max-age |
stale-while-revalidate=30 | Serve the old copy while fetching a new one |
- Some hosts also read
CDN-Cache-Control, a header only for the CDN.
Press ▶ Run. Open /prices and read the cache header in the Terminal.
- [JS] Leave out
: { name: string; price: number }.
Astro is also testing built-in route caching behind an experimental flag. Experimental features can change between versions. Read the Astro docs for your version before using it on a real site.
Simple lesson: Cache-Control tells browsers and CDNs how long they may keep a page.
Live Collections
Build-Time vs Live Collections
- Content collections (Chapter 3) load data at build time. Great for posts.
- Live collections load data on every request. Great for stock, prices, scores.
- They live in
src/live.config.ts, usedefineLiveCollection(), and need an on-demand page.
| Content collection | Live collection | |
|---|---|---|
| Config file | src/content.config.ts | src/live.config.ts |
| Define with | defineCollection() | defineLiveCollection() |
| Loaded | Once, at build time | On every request |
| Read with | getCollection(), getEntry() | getLiveCollection(), getLiveEntry() |
| Errors | Stop the build | Returned as error, you handle them |
A Live Loader
A live loader is an object with two functions:
loadCollection({ filter })returns{ entries: [...] }.loadEntry({ filter })returns one{ id, data }, or nothing when it is not found.- Either may return
{ error }instead.
Press ▶ Run. Then press Refresh a few times. The sticker stock goes down, because the data is loaded fresh on every request.
- [JS] In
live.config.js, leave outinterface Productand the type annotations.
Handling Errors
- Live data can fail: the API may be down, or an id may not exist.
getLiveCollection()andgetLiveEntry()do not throw. They return{ error }.- Always check
errorbefore usingentriesorentry.
Press ▶ Run. The mug page works. Then open /products/hat: there is no hat, so the page shows a friendly message instead of crashing.
- [JS] Leave out the
!afterAstro.params.id.
Simple lesson: live collections load on every request. Always check error first.
Choosing the Right Tool
| Situation | Best tool |
|---|---|
| Blog posts that change when you publish | Content collection, static pages |
| One personal or fast-changing box on a busy page | Server island |
| A whole page of always-fresh data | On-demand page + live collection |
| A page that can be a little old | On-demand page + Cache-Control |
| An interactive widget that reacts to clicks | Client island (Chapter 5) |
Simple lesson: static by default, a server island for one fresh part, live data for fully fresh pages.
TL;DR
- Problem = one fresh or personal part can make a whole page slow and uncacheable.
- Server island =
<Comp server:defer />. Rendered on the server, after the page. Needs an adapter. - Fallback =
<p slot="fallback">Loading…</p>shows until the island arrives. - Props = encrypted in the island URL. Data only.
- Cookies = server islands see the visitor's cookies. Personal parts on cached pages.
- Cache-Control =
public, max-age=60, s-maxage=300orprivate, no-store. - Live collection =
defineLiveCollection()insrc/live.config.ts. Loaded per request. - Read live data =
getLiveCollection()/getLiveEntry(). Checkerrorfirst.
Common mistakes
| Mistake | Wrong idea | Correct idea | What goes wrong |
|---|---|---|---|
server:defer without an adapter | It works on a static host | It needs a server | Build error |
| No fallback | The island appears at once | It loads after the page | Empty space, then a jump |
| A function as a server island prop | Props can be anything | Props are encrypted data | Error |
Astro.url inside the island for the page path | It is the page URL | It is the island URL | Wrong path; use the Referer header |
| Personal data in a CDN-cached page | Caches know who is who | A cache serves one copy to all | One visitor sees another's data |
Using entries without checking error | Live data never fails | APIs fail | The page crashes |
| A live collection on a prerendered page | Live means build time too | Live is per request | Stale or no data |
Check Yourself
Exercises
What to Remember
- One fresh or personal part should not slow down the whole page.
server:deferrenders a component later on the server. Add aslot="fallback"and an adapter.- Server island props are encrypted. Islands see the visitor's cookies.
Cache-Controldecides how long browsers and CDNs keep a page.- Live collections load data per request. Always check
error.
Next: Testing and Debugging, where you check your site before visitors find the bugs.