State & Data Caching
Relevant source files
The following files were used as context for generating this wiki page:
Farm.js provides a multi-layered caching system to optimize application performance and delivery. The framework handles static site generation (SSG), incremental static regeneration (ISR), and experimental partial prerendering (PPR) through a combination of build-time analysis and production middleware.
The system manages different types of data, including route-level HTML, dynamically generated social images, and typed content collections. It uses standard web-platform semantics like ETags and Cache-Control headers to interface with deployment targets such as Vercel and Nitro.
🔄 Rendering and Prerendering Modes
Farm.js supports three primary caching models for route segments. You configure these at the page level or via the global configuration.
Static Site Generation (SSG)
You enable SSG by exporting ssg = true from a page module. Farm.js renders these pages at build time and serves the resulting HTML as static files. This strategy offers the fastest possible load time for content that changes rarely.
Sources: examples/ssr-ssg-demo/src/app/about/page.tsx:13
Incremental Static Regeneration (ISR)
ISR allows you to update static content without rebuilding the entire site. By exporting a revalidate constant, you define the cache duration in seconds. After this period, the framework background-refreshes the page on the next request.
Sources: examples/basic/README.md:43
Partial Prerendering (PPR)
PPR is an experimental feature enabled via experimental.ppr = true. It serves a static shell immediately and then streams dynamic "islands" once the server processing completes.
Sources: examples/basic/README.md:42-45
PPR Request Flow
The following diagram shows how Farm.js handles requests when PPR is enabled.
This diagram illustrates the separation between the initial static response and the subsequent dynamic island hydration. Sources: examples/basic/README.md:40-47
🛠️ Production Cache Controls
In production, Farm.js uses Nitro-powered middleware to enforce cache contracts. The framework emits specific headers based on the route configuration.
Cache-Control Headers
The middleware sets specific Cache-Control values based on the content type:
- Immutable Assets: Fonts and social images receive
public, max-age=31536000, immutable. - ISR Routes: Use
public, s-maxage=..., stale-while-revalidate=.... - Dynamic/Private Content: Receives
private, no-store.
Sources: packages/farm/src/tests/production-middleware.test.ts:217-220, packages/farm/src/tests/docs-handler.test.ts:227-230
Validation with ETags
Farm.js generates ETags for dynamic assets like documentation social images. When a client provides an if-none-match header that matches the current ETag, the server returns a 304 Not Modified status with an empty body to save bandwidth.
Sources: packages/farm/src/tests/docs-handler.test.ts:238-245
This sequence ensures that redundant data transfers are minimized. Sources: packages/farm/src/tests/production-middleware.test.ts:178-185
📦 Content Collection Caching
The content loader system (@farm.js/content) manages the state of Markdown, MDX, and JSON collections.
Serialization and Stability
The loader serializes complex types like Date and BigInt into a stable format for the generated server module. It verifies that data does not contain circular references before serialization to prevent runtime crashes.
Sources: packages/farm-content/src/loader.test.ts:105-115, packages/farm-content/src/loader.test.ts:160-170
Asset Fingerprinting
To support long-term caching, the framework fingerprints assets referenced in content. It transforms relative paths in Markdown into emitted URL imports with content hashes.
Sources: packages/farm-content/src/loader.test.ts:200-215
| Feature | Description | Implementation |
|---|---|---|
| PPR Observability | Emits X-Farm-PPR: hit or miss headers | Middleware |
| Vary Header | Uses Vary: Accept for content negotiation (e.g., Markdown vs HTML) | app-markdown.ts |
| Fingerprinting | Appends hashes to font and image URLs | fonts.ts / loader.ts |
📊 Observability
Farm.js provides runtime events to monitor cache performance. You can subscribe to these events in farm.config.ts.
export default defineConfig({
observability: {
logs: true,
onEvent(event) {
if (event.type.startsWith("cache.") || event.type.startsWith("ppr.")) {
console.log(event); // Monitor hits/misses
}
},
},
});
Sources: examples/basic/README.md:50-63
The state management system ensures that server-side SDKs and private credentials remain isolated from the client, while public state and cached assets are delivered through optimized, browser-reachable paths.
Sources: ARCHITECTURE.md, AGENTS.md