Caching
Pulse handles asset caching automatically — production bundles are content-hashed and served with immutable cache headers. Page caching is controlled declaratively in the spec: serverTtl for in-process data, cache for HTTP headers. Nothing is cached by default unless you declare it.
serverTtl — in-process data cache
serverTtl is a number of seconds to cache the result of server.data() in memory. Subsequent requests within the TTL window skip the async data fetch entirely and serve the cached result.
export default {
route: '/homepage',
serverTtl: 60, // cache server data for 60 seconds
server: {
data: async () => ({
featured: await db.products.getFeatured(),
stats: await analytics.getGlobalStats(),
}),
},
}
| Value | Behaviour |
|---|---|
undefined (default) | No caching — server.data() runs on every request |
0 | No caching (same as undefined) |
60 | Cache for 60 seconds — at most one database hit per minute |
3600 | Cache for 1 hour |
serverTtl can mask stale data. Set it to 0 or omit it during development, and add it when deploying to production.cache — HTTP response headers
The cache field controls the Cache-Control header sent with the page HTML response. This tells browsers and CDNs how to cache the response.
export default {
route: '/blog/:slug',
cache: {
public: true, // allow CDN/proxy caching
maxAge: 300, // cache for 5 minutes
staleWhileRevalidate: 86400, // serve stale for up to 24 hours while revalidating
},
// ...
}
Cache field reference
| Field | Type | Description |
|---|---|---|
public | boolean | If true, emits public — allows CDN/proxy caching. Default: private. |
maxAge | number | Seconds before the response is considered stale. Emits max-age=N. |
staleWhileRevalidate | number | Seconds to serve stale content while revalidating in the background. Emits stale-while-revalidate=N. |
// private page — user-specific content
cache: { public: false, maxAge: 0 }
// → Cache-Control: private, no-store
// public marketing page — cached at CDN
cache: { public: true, maxAge: 3600, staleWhileRevalidate: 86400 }
// → Cache-Control: public, max-age=3600, stale-while-revalidate=86400
Default HTML caching
By default, Pulse sends Cache-Control: no-store for all HTML responses. Users always see fresh content — stale HTML is never served from browser or proxy caches unless you explicitly declare a cache policy in the spec.
Asset caching
Static assets in public/ receive Cache-Control: max-age=3600 (one hour).
Production bundles in public/dist/ receive Cache-Control: public, max-age=31536000, immutable (one year, immutable). This is guaranteed safe because bundle filenames include a content hash — code changes produce a new hash, and browsers fetch the updated file automatically. There is nothing to configure.
Development vs production
| Resource | Development | Production |
|---|---|---|
| HTML pages | no-store | no-store (or your cache config) |
Static assets (/public/*) | max-age=3600 | max-age=3600 |
JS bundles (/dist/*) | N/A (source files served directly) | immutable, max-age=31536000 |
serverTtl for expensive database queries with a short cache.maxAge and a generous cache.staleWhileRevalidate. Users get fast responses; data stays reasonably fresh.