Cache Nuxt by tag, in one line.
@canner-ca/nuxt-cache sets the Cache-Control and Surrogate-Key headers Canner needs — correctly, every time — in any Nuxt place you can set response headers: pages, server routes, and middleware. Zero dependencies.
Use it
Pages
Pass the request event. On the client useRequestEvent() is undefined, so the call is a safe no-op.
<script setup>
import { cache } from '@canner-ca/nuxt-cache';
const route = useRoute();
const { data: post } = await useAsyncData(() => fetchPost(route.params.slug));
cache(useRequestEvent(), { ttl: 3600, tags: [post.value.id, 'blog-listing'] });
</script>Server routes
In server/api or server/routes, pass the event directly.
// server/api/posts.get.ts
import { cache } from '@canner-ca/nuxt-cache';
export default defineEventHandler((event) => {
cache(event, { ttl: 3600, tags: ['blog-listing'] });
return getPosts();
});Server middleware
Mark matching paths cacheable for whatever renders them.
// server/middleware/cache.ts
import { cache } from '@canner-ca/nuxt-cache';
export default defineEventHandler((event) => {
if (event.path.startsWith('/blog/')) {
cache(event, { ttl: 3600, tags: ['blog-listing'] });
}
});Why it's safe with Nuxt
Nuxt mostly just works: client navigation fetches payloads from separate URLs, so a page URL only ever returns its HTML document. The one same-URL exception is the SPA shell Nuxt returns when a request sends x-nuxt-no-ssr — Canner's proxy passes those requests straight through, so only the real server-rendered document is ever cached. You don't configure any of that.
Options
ttlRequired. Seconds Canner may serve the cached response — sets s-maxage.tagsString, number, or array. Sets Surrogate-Key. Numbers are coerced; duplicates and whitespace tags are dropped.browserTtlOptional. Seconds the visitor's browser may cache (sets max-age). Omit to keep tag purges instant.It only ever adds headers
The helper never strips or mutates anything your app set. It does not remove Set-Cookie — Canner already declines to cache a response that sets a cookie, so you get a development-only warning, and your cookie is left untouched. A bad TTL sets no headers and warns; a null target is a no-op (the client render pass); only an unsupported target throws.
Then point your CMS at Canner
The code side is done. The other half is two copy-paste values — the webhook URL and an Authorization header — shown pre-filled in the dashboard under Settings → Caching. Full caching guide.
Source and issues: tools/nuxt-cache/ in the canner repo on GitHub. Licensed MIT. Also available for @canner-ca/astro-cache and @canner-ca/next-cache.