Blog
Published at: Aug 3, 2026
Static file caching in Nuxt: a practical strategy

Static file caching in Nuxt: a practical strategy

Sadeq Sheikhi
Sadeq Sheikhi

Lighthouse kept warning me about inefficient cache lifetimes, even though I had already added caching for my static files. The missing piece was Nuxt Image and its generated <code>/_ipx</code> URLs. In this post, I’ll share the simple caching setup I use for Nuxt build files, public assets, and optimized images without risking stale content after deployment.

Cache files aggressively when changing the file also changes its URL. Be more careful when the same URL can serve different content later.

You have probably seen the same Lighthouse warning I have:

“Use efficient cache lifetimes.”

Browser caching for static files is usually straightforward. You add a Cache-Control header, choose a reasonable lifetime, and the browser avoids downloading the same files again on every visit.

However, in a Nuxt application, not every static-looking file should use the same caching policy.

Nuxt build files are automatically versioned. Files inside public/ usually are not. Nuxt Image also creates transformed image URLs under /_ipx, which need their own cache rule.

In this post, I will share the setup I use, including the Nuxt Image rule that was missing during my latest Lighthouse audit.

The simple caching rule

The most important question is not whether a file is an image, font, or JavaScript file.

The important question is:

Will the URL change when the file changes?

When the answer is yes, you can safely cache the file for a very long time.

When the answer is no, you should use a shorter cache lifetime. Otherwise, visitors may continue seeing an old version after you deploy an update.

What the cache directives mean

Here are the main directives used in this setup:

  • public allows browsers and shared caches such as CDNs to store the response.
  • max-age controls how long the browser considers the file fresh.
  • s-maxage controls how long shared caches, such as Cloudflare, consider it fresh.
  • immutable tells the browser that the file will never change while it is cached.

You should only use immutable when a changed file receives a new URL.

The three main asset types in Nuxt

1. Nuxt build files: /_nuxt/**

Nuxt and Vite generate filenames that include a content hash, for example:

/_nuxt/entry.Bx3k9Qp2.js

When the contents of the file change, the hash changes too, which creates a new URL.

This makes Nuxt build files safe to cache for a year with immutable. The old file can stay cached because the next deployment will reference a completely different filename.

2. Files inside public/

Files placed inside Nuxt’s public/ directory are served directly from the root of the website.

For example:

public/img/logo.png

becomes:

/img/logo.png

The problem is that the URL usually stays the same after deployment.

If you replace the logo but keep the same filename, a visitor may continue seeing the old version until the cache expires.

For these files, you have two options:

  • Use a reasonable cache lifetime, such as a few days or weeks.
  • Add a version to the filename, such as logo.v2.png or logo.2026-08.png.

Once the filename is versioned, you can safely give it a much longer cache lifetime.

3. Nuxt Image files: /_ipx/**

When using Nuxt Image with the local IPX provider, the browser does not always request the original image directly.

Instead, Nuxt creates a transformed URL similar to this:

/_ipx/q_80&s_640x360/projects/sharmarket.webp

The URL includes the requested size, quality, and source image path. This allows every image size and format to be cached separately.

This was the part missing during my latest Lighthouse audit.

I already had cache rules for files under /img, but Lighthouse was reporting the generated /_ipx URL instead. The original image and the transformed Nuxt Image response are two different requests, so they need separate route rules.

There is one important detail: the IPX URL is not fully immutable by default.

If you replace the source image while keeping the same source path, the generated /_ipx URL may stay the same while returning new content.

Because of that, I cache IPX responses for a month, but I do not mark them as immutable.

The Nuxt route rules

I keep these rules inside my shared Nuxt configuration so that all applications extending the base layer receive the same caching behaviour.

routeRules: {
  '/_nuxt/**': {
    headers: {
      'cache-control':
        'public,max-age=31536000,s-maxage=31536000,immutable',
    },
  },

  '/_ipx/**': {
    headers: {
      'cache-control':
        'public,max-age=2592000,s-maxage=2592000',
    },
  },

  '/img/**': {
    headers: {
      'cache-control':
        'public,max-age=864000,s-maxage=864000',
    },
  },

  '/fonts/**': {
    headers: {
      'cache-control':
        'public,max-age=5184000,s-maxage=5184000',
    },
  },

  '/js/**': {
    headers: {
      'cache-control':
        'public,max-age=2592000,s-maxage=2592000',
    },
  },
}

These values translate roughly to:

  • /_nuxt/**: one year
  • /_ipx/**: thirty days
  • /img/**: ten days
  • /fonts/**: sixty days
  • /js/**: thirty days

They are not universal values. They are simply practical defaults based on how often those files are likely to change.

Why the IPX rule matters

A rule for /img/** only affects the original public image.

It does not automatically affect a transformed image returned from /_ipx/**.

For example, these are separate requests:

/img/project.webp

/_ipx/q_80&s_640x360/img/project.webp

The browser, Lighthouse, and your CDN treat them as different URLs.

So when Lighthouse reports a poor cache lifetime for a Nuxt Image asset, inspect the actual URL. In many cases, the missing rule is /_ipx/**, not the original image folder.

Do not use immutable everywhere

It can be tempting to add a one-year cache to every static file just to make Lighthouse happy.

That can create problems during the next deployment.

For example, imagine that you cache /img/logo.png for one year with immutable. A week later, you replace the logo without changing the filename.

Some visitors may continue seeing the old logo because their browser was explicitly told that the file would not change.

A better approach is:

  • Use long immutable caching for hashed or versioned URLs.
  • Use shorter caching for files whose URLs may be reused.
  • Rename files when you need immediate and reliable invalidation.

Cloudflare and CDN caching

Nuxt route rules set the response headers at your application server, but a CDN such as Cloudflare sits in front of it.

Cloudflare may respect those headers, override them, or decide that a response is not eligible for caching.

After deployment, check the real response instead of assuming the configuration is working.

You can use:

curl -I https://example.com/_ipx/q_80&s_640x360/projects/sharmarket.webp

Look for the cache-control header and, when using Cloudflare, headers such as cf-cache-status.

Also check whether a Cloudflare Cache Rule or Worker is replacing your origin headers.

A practical default strategy

  • Hashed Nuxt build files: one year with immutable.
  • Versioned public files: one year with immutable.
  • Normal public images and scripts: several days or weeks without immutable.
  • Nuxt Image IPX responses: several weeks without immutable, unless the source image paths are also versioned.

How to verify the setup

  1. Open the Network tab in your browser’s developer tools.
  2. Inspect a file under /_nuxt.
  3. Inspect an original image under /img.
  4. Inspect the generated Nuxt Image request under /_ipx.
  5. Confirm that each response has the expected cache-control header.
  6. Run Lighthouse again after deploying the changes.

Lighthouse is useful for finding missing cache rules, but the goal should not be to make every asset immutable.

The goal is to cache files for as long as their URL structure safely allows.

Conclusion

The strategy is simple:

Nuxt’s hashed build files can be cached for a very long time because every change creates a new URL.

Files inside public/ need more care because their URLs usually remain the same. Nuxt Image responses under /_ipx also need a separate rule, which was the missing part in my own Lighthouse audit.

Once you separate these asset types, static file caching in Nuxt becomes much easier to reason about, and you can improve repeat visits and Lighthouse results without accidentally serving stale files for months.

FAQ

Sadeq Sheikhi
Sadeq Sheikhi

Hi, Im a seniour software engineer building web platforms. I write about Nuxt, Typescript, DevOps, AI and engineering decisions behind real products, based on my real experience.

Read More

If You Build Multiple Applications, Nuxt Layers Are Your Lifesaver

Nuxt layers let you package reusable parts of your application — components, configuration, plugins, server APIs, authentication, payments, and more — so every new project starts with your best work already in place.

Stop Letting i18n Drift: Build a Checker Your AI Agent Can Actually Use

Working on a multilingual website with hundreds of translation keys is never simple. Keys get missed in some locales, and hardcoded strings inevitably remain in the codebase. This is the workflow I use—a small Python checker paired with an AI agent—to find those problems, fix the real issues, and verify the result automatically.

Sadeq Sheikhi

Senior Vue/Nuxt Developer and Full-Stack Product Engineer


© 2026 Sadeq Sheikhi. Built with Nuxt.