npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@onderwijsin/nuxt-cache

v0.2.5

Published

Cache metadata indexing and targeted invalidation for Nitro storage.

Readme

@onderwijsin/nuxt-cache

@onderwijsin/nuxt-cache adds cache-entry metadata and a reverse path index to an Unstorage driver. It also provides a protected, cache-base-scoped invalidation endpoint. It is CMS-agnostic: mapping a content event to a cache base and public route remains the consuming application's responsibility.

Requires Nuxt 4 and Node.js 24 or later. Node.js 22 may work but is untested and unsupported.

Installation

pnpm add @onderwijsin/nuxt-cache unstorage

The driver modules below import unstorage directly, so it is a required application dependency. For Redis or Valkey, also install its Unstorage peer dependency:

pnpm add ioredis
export default defineNuxtConfig({
  modules: ["@onderwijsin/nuxt-cache"],
  cache: {
    enabled: true,
    adminToken: process.env.CACHE_ADMIN_TOKEN
  }
});

The module is disabled by default. It does not take over the application's cache mount. Register the driver in the application so existing storage ownership, credentials, and deployment decisions remain explicit.

Cache identity and records

The cache module follows Nitro's route-rule cache identity convention. A cache base is always <group>:<name>, and cache entries under that base must begin with <group>:<name>:. For example, the cache identity kennisbank:articles owns keys such as kennisbank:articles:example-slug:abc123.

For every wrapped cache value, the driver stores:

value:     kennisbank:articles:<suffix>
metadata:  kennisbank:articles:<suffix>$
index:     __cache_meta:index:v1:kennisbank:articles:<encoded-path>:<encoded-key>

storage.getMeta(key) returns the native driver metadata together with cache metadata: { version: 1, path: "/public/route" }. The sidecar and index receive the same Unstorage options as the value, including TTL. Normal removeItem() operations remove all related records.

Driver registration

Create a Nitro driver module and reference it from nitro.storage.cache.driver. The cache wrapper adds path metadata and a reverse index while preserving the underlying driver's normal operations.

Filesystem

// server/storage/cache-driver.mjs
import { createCacheDriver } from "@onderwijsin/nuxt-cache/runtime";
import { defineDriver } from "unstorage";
import fsDriver from "unstorage/drivers/fs";

export default defineDriver((options) => createCacheDriver(fsDriver(options)));

Redis or Valkey

// server/storage/cache-driver.mjs
import { createCacheDriver } from "@onderwijsin/nuxt-cache/runtime";
import { defineDriver } from "unstorage";
import redisDriver from "unstorage/drivers/redis";

export default defineDriver((options) => createCacheDriver(redisDriver(options)));
// nuxt.config.ts
import { fileURLToPath } from "node:url";

export default defineNuxtConfig({
  modules: ["@onderwijsin/nuxt-cache"],
  nitro: {
    storage: {
      cache: {
        driver: fileURLToPath(new URL("./server/storage/cache-driver.mjs", import.meta.url)),
        url: process.env.REDIS_URL
      }
    }
  }
});

Cloudflare KV binding

Cloudflare KV bindings do not provide native bulk deletion. Use the Cloudflare-specific wrapper so storage.clear(base) sends bulk-delete requests for value, metadata, and index records. The wrapper lists only the requested base and its module-owned index prefix, deduplicates the resulting keys, and sends Cloudflare's maximum 10,000 keys per request.

// server/storage/cache-driver.mjs
import { createCloudflareCacheDriver } from "@onderwijsin/nuxt-cache/runtime";
import { defineDriver } from "unstorage";
import cloudflareKVBindingDriver from "unstorage/drivers/cloudflare-kv-binding";

export default defineDriver(({ accountId, kvApiToken, cacheNamespaceId, ...driverOptions }) =>
  createCloudflareCacheDriver(cloudflareKVBindingDriver(driverOptions), {
    accountId,
    kvApiToken,
    cacheNamespaceId
  })
);
// nuxt.config.ts
import { fileURLToPath } from "node:url";

export default defineNuxtConfig({
  modules: ["@onderwijsin/nuxt-cache"],
  nitro: {
    storage: {
      cache: {
        driver: fileURLToPath(new URL("./server/storage/cache-driver.mjs", import.meta.url)),
        binding: "CACHE",
        accountId: process.env.CLOUDFLARE_ACCOUNT_ID,
        kvApiToken: process.env.CLOUDFLARE_KV_API_TOKEN,
        cacheNamespaceId: process.env.CLOUDFLARE_CACHE_NAMESPACE_ID
      }
    }
  }
});

setItems() writes the batch with the underlying driver and then records metadata/indexes for every cache value. The generic wrapper retains the underlying driver's clear() behavior. The Cloudflare wrapper customizes clear() because KV needs the provider bulk-delete API; use a complete <group>:<name> cache base when clearing a Cloudflare cache.

Invalidation API

POST /api/_cache/invalidate
Content-Type: application/json
x-admin-token: <adminToken>
{
  "targets": [
    {
      "base": "kennisbank:articles",
      "path": "/kennisbank/artikelen/example-slug",
      "match": "prefix"
    }
  ]
}

base is required and must be <group>:<name>. The endpoint reads only index records for that base; it never scans the complete cache mount or matches cache-key strings. match is exact by default and also accepts prefix. Prefix matching includes the exact path and descendants separated by /; invalidating /articles/foo does not invalidate /articles/foobar. The response is { "data": { "removed": number } }.

For prefix matching, one trailing slash is ignored: /articles/foo/ behaves as /articles/foo. The root path / matches every absolute cached route in the requested base.

The endpoint lazily removes stale index records when a cache value has expired or a previous write did not complete. An invalidation request is limited by maxInvalidatedEntries before it deletes any records.

Production requests require either the configured adminHeaderName (default x-admin-token) or Authorization: Bearer <adminToken>. Set devAuthBypass: true only for a trusted local server; it allows unauthenticated invalidation during development and logs a warning.

Configuration

| Option | Default | Description | | ----------------------- | --------------- | --------------------------------------------------- | | enabled | false | Registers the invalidation API. | | adminToken | — | Required production administrator token. | | adminHeaderName | x-admin-token | Header carrying the administrator token. | | devAuthBypass | false | Allows unauthenticated invalidation in development. | | maxInvalidatedEntries | 1000 | Maximum index records one request can remove. |

The module stores its private server runtime values under runtimeConfig.nuxtCache. This namespace is reserved for the module; configure the public module options through the cache key shown above instead of setting runtimeConfig.nuxtCache directly.

Boundaries and troubleshooting

@onderwijsin/nuxt-cache does not implement generic cache browsing or CRUD. Use @onderwijsin/nuxt-storage-admin when an operational tool needs explicitly allowlisted storage access. It also does not translate CMS events: a consumer-owned webhook should map a CMS event to a known cache base and public path, then call /api/_cache/invalidate.

Reserve /api/_cache/** for this module while it is enabled. If an entry has no metadata, ensure its key begins with a valid cache base and that it was written while a Nitro request context was active (or pass getRequestPath when creating the driver outside a request).

Compatibility

Developed and tested against Node.js 24 and Nuxt 4.5.x. The package declares Node.js >=24 and may work with other Nuxt versions permitted by its package metadata, but versions outside the current CI matrix are not continuously tested. Nuxt 3 is not guaranteed.