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!

Comments