DEV Community

Rahil Khan
Rahil Khan

Posted on

Repeat visitors shouldn't re-download your logo: Cache-Control headers for small-business sites in 10 minutes

Every time someone opens your site a second time, their browser asks: "do I still have a good copy of this logo, this CSS, this font?" If your server never answers that question, the browser plays safe and downloads everything again. On a small-business site with a big hero photo and a couple of web fonts, that's often 1–3 MB per visit wasted, and it's the people on slow mobile data who feel it most.

The fix is one HTTP header: Cache-Control.

1. Check what you're sending now

Open your site, then DevTools → Network, reload, click your logo or main CSS file and look at Response Headers. Or from a terminal:

curl -sI https://yoursite.com/images/logo.png | grep -i -E "cache-control|expires|etag"
Enter fullscreen mode Exit fullscreen mode

No Cache-Control at all, or max-age=0 on images and fonts, means repeat visitors re-download them.

2. The simple rule set

  • HTML pages: short or no cache, so content updates show up right away: Cache-Control: no-cache (the browser keeps a copy but checks with the server first).
  • Images, fonts, CSS, JS that change rarely: cache for a long time: Cache-Control: public, max-age=31536000, immutable only if the file name changes when the file changes (e.g. style.3f9a1c.css, which most build tools do for you).
  • Static files without versioned names (a plain logo.png you might replace): something moderate like max-age=604800 (7 days).

3. Copy-paste configs

Apache (.htaccess, common on shared hosting):

<IfModule mod_headers.c>
  <FilesMatch "\.(png|jpe?g|webp|svg|woff2|ico)$">
    Header set Cache-Control "public, max-age=604800"
  </FilesMatch>
  <FilesMatch "\.(html)$">
    Header set Cache-Control "no-cache"
  </FilesMatch>
</IfModule>
Enter fullscreen mode Exit fullscreen mode

Nginx:

location ~* \.(png|jpe?g|webp|svg|woff2|ico)$ {
  add_header Cache-Control "public, max-age=604800";
}
Enter fullscreen mode Exit fullscreen mode

Netlify (_headers file in your publish folder):

/images/*
  Cache-Control: public, max-age=604800
/assets/*
  Cache-Control: public, max-age=31536000, immutable
Enter fullscreen mode Exit fullscreen mode

Vercel (vercel.json):

{
  "headers": [
    {
      "source": "/images/(.*)",
      "headers": [{ "key": "Cache-Control", "value": "public, max-age=604800" }]
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

WordPress: most caching plugins have a "browser caching" toggle that writes the Apache rules above for you.

4. Verify

Reload twice with DevTools open. On the second load, images and fonts should show (memory cache) or (disk cache) in the Size column instead of a download size.

The one mistake to avoid

Don't put a one-year immutable cache on a file you'll later overwrite with the same name. Visitors will keep the old version for months. Long caches are for versioned file names only.

Ten minutes of config, and every returning customer gets a noticeably faster site.


NEXCOD builds and fixes fast websites for small businesses. nexcod.vercel.app · WhatsApp +1 289 902 5119

Top comments (0)