DEV Community

Mohsen Fallahnejad
Mohsen Fallahnejad

Posted on Edited on Originally published at bitlyst.blog

CDN Explained: What It Is, How It Works, and How to Use It in Next.js

A CDN (Content Delivery Network) is a global network of servers that cache and serve your static assets β€” JS, CSS, images, fonts β€” from a location close to the user.

Without a CDN, every user hits your origin server (wherever it's hosted).

With a CDN, they hit the nearest edge node instead.


🌍 How It Works

User (Tokyo) β†’ CDN Edge (Tokyo)
  β”œβ”€ Cache HIT βœ“ β†’ Instant Response
  └─ Cache MISS β†’ Origin Server β†’ Cache β†’ Respond
Enter fullscreen mode Exit fullscreen mode
  1. User requests /logo.png
  2. CDN checks its edge cache
  3. Cache hit β†’ served immediately from edge
  4. Cache miss β†’ CDN fetches from your origin, caches it, serves it

Next request from any user near that edge? Instant.


πŸ“¦ What Gets Cached?

Asset type Cached by CDN?
JS / CSS bundles βœ…
Images / fonts βœ…
HTML (static) βœ…
API responses ⚠️ optional
Dynamic SSR pages ⚠️ optional

⚑ Why It Matters for Frontend

  • Lower latency β€” assets served from 50ms away, not 300ms
  • Less load on your server β€” CDN absorbs most traffic
  • Better Core Web Vitals β€” faster LCP, less layout shift
  • Global scale β€” same performance in Tokyo as in London

πŸ”§ CDN in Next.js

Next.js is CDN-ready out of the box. Here's what gets cached automatically:

Static assets in /public

Served with long-lived cache headers automatically.

next/image

Images are optimized and served via CDN edge with proper Cache-Control.

Static pages (SSG)

Pages generated at build time are cached at the CDN edge.


βš™οΈ Configuration

1. Custom CDN with assetPrefix

If you're using your own CDN (Cloudflare, CloudFront, etc.):

// next.config.js
module.exports = {
  assetPrefix: 'https://cdn.yourdomain.com',
}
Enter fullscreen mode Exit fullscreen mode

Next.js will now load all /_next/static/ assets from your CDN URL.


2. Cache-Control headers

// next.config.js
module.exports = {
  async headers() {
    return [
      {
        source: '/static/(.*)',
        headers: [
          {
            key: 'Cache-Control',
            value: 'public, max-age=31536000, immutable',
          },
        ],
      },
    ]
  },
}
Enter fullscreen mode Exit fullscreen mode
  • max-age=31536000 β†’ cache for 1 year
  • immutable β†’ browser won't revalidate even on hard refresh

3. Per-fetch CDN caching (App Router)

// cached for 1 hour at the CDN edge
const data = await fetch('https://api.example.com/posts', {
  next: { revalidate: 3600 },
})
Enter fullscreen mode Exit fullscreen mode

4. Page-level revalidation (ISR)

// app/blog/page.tsx
export const revalidate = 60 // revalidate every 60 seconds
Enter fullscreen mode Exit fullscreen mode

CDN serves the cached page, Next.js regenerates it in the background when stale.


5. Force static caching

export const dynamic = 'force-static'
Enter fullscreen mode Exit fullscreen mode

Tells Next.js (and the CDN) to never recompute β€” serve the static version always.


🧠 Cache-Control Cheat Sheet

Header value Meaning
public, max-age=31536000, immutable Cache forever (versioned assets)
public, s-maxage=3600 CDN cache for 1 hour
no-store Never cache
stale-while-revalidate=60 Serve stale, refresh in bg

✨ Final Takeaway

A CDN puts your assets next to your users. Next.js handles most of it automatically β€” configure assetPrefix for custom CDNs, and use revalidate to control how long pages stay cached at the edge.


Originally published on Bitlyst.

Top comments (0)