CDNs don’t just cache static assets; they can dramatically speed up dynamic API responses by caching them at the edge, often making your API faster than if the user hit your origin server directly.

Let’s see this in action. Imagine an API endpoint /users/123 that returns a user’s profile. Without CDN caching, every request for user 123 goes all the way to your backend server.

# User request hits origin server
curl -v https://myapi.com/users/123

Now, with CDN edge caching configured for this endpoint, the first request might still hit your origin. But the CDN, seeing it’s a cacheable response, stores it at an edge location close to the user.

# First request - hits origin
curl -v https://myapi.com/users/123
# CDN caches response for /users/123 for 60 seconds

# Second request (within 60 seconds) - served from CDN edge
curl -v https://myapi.com/users/123
# Response is served from the edge, often < 50ms latency

The magic is in how you tell the CDN what to cache and for how long. This is typically done via HTTP headers returned by your API.

Key Headers for API Caching:

  • Cache-Control: This is the primary directive. For API responses, you’ll often use:

    • public: Allows caching by any cache, including CDNs.
    • max-age=<seconds>: Specifies how long the response is fresh. For user profiles, maybe max-age=60 (1 minute) is appropriate.
    • s-maxage=<seconds>: Similar to max-age but specifically for shared caches (like CDNs). If both max-age and s-maxage are present, s-maxage takes precedence for CDNs.
    • stale-while-revalidate=<seconds>: Allows the CDN to serve a stale (expired) response while it asynchronously revalidates with the origin in the background. This improves perceived performance for users even when the cache is technically expired.
    • stale-if-error=<seconds>: Allows the CDN to serve a stale response if the origin returns an error.
  • Vary: This header is critical for dynamic content. It tells the CDN which request headers should be considered when determining cache uniqueness. For example, if your API returns different data based on the Accept-Language header, you’d include Vary: Accept-Language. If it’s personalized based on Authorization, you cannot cache it directly with Authorization in the Vary header. This is where more advanced strategies come in.

Example Backend Configuration (Node.js/Express):

app.get('/users/:id', (req, res) => {
  const userId = req.params.id;
  // Fetch user data from your database
  const userData = getUserFromDB(userId); // Assume this returns user data

  if (!userData) {
    return res.status(404).send('User not found');
  }

  res.setHeader('Cache-Control', 'public, max-age=60, s-maxage=120, stale-while-revalidate=30');
  res.setHeader('Vary', 'Accept-Language'); // If content changes based on language
  res.json(userData);
});

In this example, the response is public, fresh for 60 seconds (max-age), and the CDN can keep it for 120 seconds (s-maxage). It can also serve a stale response for up to 30 seconds while revalidating. The Vary: Accept-Language means the CDN will cache /users/123 separately for en-US and fr-FR.

The Challenge with Personalized Data:

Directly caching responses that depend on the Authorization header is a security risk and generally not possible. The Authorization header would need to be in the Vary header, leading to an explosion of cache entries or, more commonly, the CDN refusing to cache it.

Advanced Strategy: Cache Keys and Edge Compute

This is where CDNs like Cloudflare Workers, AWS Lambda@Edge, or Akamai EdgeWorkers shine. You can intercept requests at the edge and compute a unique cache key based on specific parts of the request (e.g., user ID from a JWT without sending the Authorization header to the origin).

  1. Edge Logic: A small piece of code runs on the CDN edge.
  2. Extract Cache Key: It parses the Authorization token (e.g., JWT) to extract the user ID.
  3. Construct Cache Key: It creates a cache key like api/users/<userId>/<resourceId>.
  4. Cache Lookup: It checks if a response exists for this specific cache key.
  5. Origin Fetch (if miss): If not found, it forwards the request to the origin, but crucially, it attaches the original Authorization header so the origin can authenticate and personalize the response.
  6. Cache Stash: The origin’s response is then stored at the edge using the computed cache key, not the raw request URL.

This allows highly personalized API data to be cached effectively. For instance, a user’s dashboard data could be cached per user ID, meaning subsequent requests from that same user for their dashboard are served directly from the edge, bypassing your backend entirely for the duration of the max-age.

The most surprising aspect of API caching on CDNs is how much control you have over what constitutes a unique cacheable item. It’s not just the URL; it’s a combination of headers and potentially even parts of the request body that you can instruct the CDN to consider, allowing for complex personalization to be aggressively cached.

The next hurdle is understanding how to invalidate these caches when data changes on the origin.

Want structured learning?

Take the full Cdn course →