Caching in Remix with `createHeadersFunction`Chris Child | 2025-04-03 | 2 min read| Comments
Efficient caching improves performance by reducing server load and speeding up page loads. In my Remix blog, I use createHeadersFunction
to handle caching in a structured way. Here's how it works.
Why Caching Matters
Without caching, every request triggers server processing, which is inefficient. By setting Cache-Control
headers, we let browsers and CDNs cache responses for a defined period, reducing redundant work.
The createHeadersFunction
To simplify caching, I created createHeadersFunction
, which returns a HeadersFunction
based on a cache type. Here's the full implementation:
import type { HeadersFunction } from '@remix-run/node'
// Cache durations:
// SHORT: 1 minute
// MEDIUM: 1 hour
// LONG: 1 day
// FOREVER: 1 year, immutable
// NO_CACHE: No caching
type CACHE = 'SHORT' | 'MEDIUM' | 'LONG' | 'FOREVER' | 'NO_CACHE'
export function createHeadersFunction(cacheType: CACHE): HeadersFunction {
switch (cacheType) {
case 'SHORT':
return () => ({
'Cache-Control': 'public, max-age=60, stale-if-error=31536000',
})
case 'MEDIUM':
return () => ({
'Cache-Control': 'public, max-age=3600, stale-if-error=31536000',
})
case 'LONG':
return () => ({
'Cache-Control': 'public, max-age=86400, stale-if-error=31536000',
})
case 'FOREVER':
return () => ({
'Cache-Control': 'public, max-age=31536000, immutable, stale-if-error=31536000',
})
case 'NO_CACHE':
default:
return () => ({
'Cache-Control': 'no-store, no-cache, must-revalidate',
Pragma: 'no-cache',
})
}
}
Cache Strategy
SHORT
(1 min): For frequently updated content.MEDIUM
(1 hour): For periodically updated pages.LONG
(1 day): For content that changes daily (e.g., blog posts).FOREVER
(1 year, immutable): For static assets.NO_CACHE
: Ensures fresh content for dynamic pages.
Each option includes stale-if-error=31536000
, allowing stale content to be served for a year if the server is down.
Using It in Remix
In my Remix routes, I apply caching like this:
import { createHeadersFunction } from '~/utils/cacheHeaders';
export const headers = createHeadersFunction('LONG');
This keeps my caching logic clean and consistent across the blog.
Final Thoughts
With createHeadersFunction
, I manage caching efficiently using a simple API. It ensures my blog serves content quickly while reducing server load. If you're using Remix, implementing a similar strategy can greatly improve performance!