Guides

Cache invalidation

Cache public SSR responses and invalidate by URL, tag, host, or rule.

Nitroship's optional Edge response cache stores public function/SSR responses using your app's HTTP headers. It is separate from prerender/ISR and the framework data cache. Your operator must enable the response cache; when it is disabled, these headers do not activate it and no response-cache status header is added.

For ISR and prerendered pages, ntro purge bumps the generation so the next request uses a fresh result. The same command also invalidates matching response-cache entries when that feature is enabled.

Cache a public SSR response

Send an Edge policy alongside the browser policy:

Cache-Control: public, max-age=0, must-revalidate
CDN-Cache-Control: public, s-maxage=60, stale-while-revalidate=120, stale-if-error=300
Nitroship-Cache-Tag: articles, article:42

Nitroship chooses the first present policy header in this order: Nitroship-CDN-Cache-Control, CDN-Cache-Control, then Cache-Control. It does not merge policies or fall back from an uncacheable higher-priority header. The CDN-only headers accept s-maxage, or max-age if s-maxage is absent. Cache-Control alone needs s-maxage; browser max-age alone does not enable the Edge cache. private, no-store, no-cache, or a nonpositive TTL in the chosen header prevents storage.

With this example, an entry is fresh for 60 seconds. After that, stale-while-revalidate can serve the old response while a background render refreshes it for another 120 seconds. stale-if-error allows an old response within 300 seconds after freshness ends when a background regeneration failure has been recorded (5xx or timeout). Each duration is capped at 31,536,000 seconds, but actual retention never exceeds the 30-day hard cap below.

When enabled, Nitroship removes the CDN-only policy headers and Nitroship-Cache-Tag before responding to visitors. If the chosen policy is Cache-Control, its s-maxage, stale-while-revalidate, and stale-if-error directives are removed from the visitor value. If a CDN-only header supplies the policy, the original browser Cache-Control is preserved.

Next.js

For public SSR routes, set CDN-Cache-Control using next.config's headers() or middleware. Do not rely on Next.js's generated Cache-Control being your Edge policy. For example, in next.config.mjs:

export default {
  async headers() {
    return [{
      source: '/cached/:path*',
      headers: [
        {
          key: 'CDN-Cache-Control',
          value: 'public, s-maxage=60, stale-while-revalidate=120, stale-if-error=300',
        },
        { key: 'Nitroship-Cache-Tag', value: 'articles' },
      ],
    }];
  },
};

Middleware can instead set CDN-Cache-Control and Nitroship-Cache-Tag on the response for the intended routes. Only opt in routes whose output is safe to share. The repository's examples/hello-ssr-cache demonstrates dynamic render timestamps, host-specific output, and tags. See Next.js.

Eligibility and limits

  • Requests must be GET or HEAD, without Authorization or Range. HEAD uses the GET cache.
  • Supported response status codes are 200, 301, 302, 307, 308, 404, and 410. Responses with Set-Cookie are not stored.
  • With Content-Length, the body limit is 10,000,000 bytes (decimal 10 MB). Without it, including chunked streams, the limit is 20,000,000 bytes (decimal 20 MB).
  • If a body exceeds its limit or the compute node's memory capture budget, Nitroship stops capturing and does not store it; the visitor's response continues streaming. Bodies are never captured to server disk.
  • Vary: * and Vary: Cookie are not cached. Other Vary headers select separate variants. The key also includes scheme, host (case-insensitive, without port), path, full query, Accept, and normalized Accept-Encoding. Two hosts serving the same path do not share entries.
  • Cookies on the request alone do not guarantee a bypass. Never opt personalized output into a public cache; use private or no-store.
  • Nitroship-Cache-Tag accepts comma-separated, trimmed, case-sensitive tags. Empty values are ignored and duplicates are removed. There can be 128 tags per response, each at most 256 UTF-8 bytes, with no NUL, CR, or LF. Invalid tags prevent storage; they are not truncated.

Retention is best-effort, up to 30 days from generation, not a storage guarantee. Entries may be lost sooner. Even a longer TTL, SWR, or SIE cannot make an entry older than 30 days usable.

Read the cache status

When enabled, responses expose x-nitroship-cache:

ValueMeaning
HITA fresh cached response was served.
STALEAn old response was served under SWR, invalidation, or stale-if-error.
MISSNo usable response was available; the function was invoked.
BYPASSThe request bypassed response caching, for example because it was ineligible or a pointer lookup failed.
REVALIDATEDA synchronous render followed a response-cache delete.

This is the SSR cache status, not the CDN cache status of a stored file. A MISS is not a promise that the returned response will be stored.

Invalidate or delete

ntro purge chooses exactly one selector type: exact URL or path, prefix, glob pattern, tags, host, or the entire app. --tag can be repeated, with at most 16 tags per purge request. The same 256 UTF-8 byte limit applies to each purge tag.

Usage

There are six selector types, and you can use only one at a time.

ntro purge /docs/page --app my-app --wait
ntro purge --prefix /docs/ --app my-app
ntro purge --glob '/assets/**' --app my-app
ntro purge --all --app my-app --yes
ntro purge --tag articles --tag article:42 --app my-app --wait
ntro purge --host www.example.com --app my-app --wait
ntro purge --tag article:42 --delete --app my-app --wait

Paths beginning with / are resolved against the app's production alias. An absolute URL or --host hostname must belong to the app. A host selector targets the response cache for that host. Purging the entire app requires confirmation. --wait waits for invalidation to be applied at active edges, not for a background render to finish. Without --wait, the CLI does not wait.

In a folder without an app link, add --app <app-name>. The examples above specify it explicitly.

What is and is not cleared

The default mode is invalidate: a matching response-cache entry becomes stale, so visitors can receive its old contents while Nitroship regenerates it in the background, even if no SWR was configured. Add --delete to stop serving the previous entry and require a synchronous render on the next request. Delete takes precedence over invalidation, and neither mode can serve an entry past its 30-day hard cap.

Existing prerender/ISR purges keep their generation-change behavior in either mode; --delete does not change the framework data-cache contract. Neither mode physically deletes stored or CDN-cached files, and --wait does not certify CDN file deletion. App permanent deletion has a separate storage/CDN cleanup process. Create a new deployment when changing immutable static files. See Deployments and promotion.

On this page