Verified against Claude Code · 2026-07-27
Pick a revalidation strategy instead of defaulting every page to revalidate: 60
Matches ISR revalidation to how content actually changes — on-demand via revalidateTag, time-based sized to real update frequency, or no caching at all — instead of a copy-pasted 60-second default.
The prompt
Ready to copy — highlighted parts are example details you can swap.
You are recommending a revalidation strategy for a specific piece of content, grounded in how that content source actually behaves rather than a guessed round-number interval. CONTENT TYPE AND SOURCE Product detail pages, backed by a headless commerce CMS UPDATE FREQUENCY Prices and stock counts update several times a day; product descriptions and images rarely change after launch TRAFFIC PATTERN Most traffic goes to the top 200 best-selling products; the long tail of older listings gets occasional search traffic WEBHOOK AVAILABILITY Yes — the commerce platform supports a product.updated webhook CURRENT REVALIDATION SETTING revalidate: 60 is set at the top of every product page file, copied from an early prototype DECISION FRAMEWORK If the content source can fire a webhook on publish or update, prefer on-demand revalidation: call revalidateTag, tagged per content item rather than one tag covering the whole collection, from a Route Handler the webhook hits, instead of guessing at a time interval that will either be too slow for a real change or too frequent for a quiet week. This keeps pages fresh immediately on an actual change and avoids serving stale content for the length of an arbitrary time window between real updates. If no webhook is available, use time-based revalidation — the route segment's revalidate export or fetch's next.revalidate option — but size the interval to the stated update frequency rather than a round default; content that changes a handful of times a day doesn't need a 60-second check, and a 60-second check on content that changes weekly just refetches identical data on a schedule for no benefit. For pages with heavy traffic and rarely-changing content, a longer revalidate window combined with an on-demand revalidateTag or revalidatePath call for the rare actual update is usually a better fit than a short polling-style interval that spends most of its checks re-serving the same cached page anyway. Flag any content where staleness carries a real cost — pricing, live inventory counts, an account's current status — as a candidate for no caching at all, or a very short window scoped only to that specific field, rather than forcing ISR onto something that genuinely needs to be live on every request. OUTPUT FORMAT A recommendation with the specific revalidate value, or the revalidateTag/webhook design if on-demand is the right fit, one sentence justifying the choice against the stated update frequency and traffic pattern specifically, and a note on which cache tags to use, at what granularity, if on-demand revalidation applies here.
Customize
Optional — swap in your own details for the highlighted parts above.
Why this works
A flat revalidate: 60 is the single most copy-pasted line in ISR examples, and it's usually wrong in both directions at once for the same reason: it's too slow for content that just changed and needs to be live immediately, and too frequent for content that only changes a few times a week, which means most of those 60-second checks refetch identical data for zero user-visible benefit while still paying the cost of a network round trip on the server. Framing the choice as a decision tree — webhook available means prefer on-demand revalidateTag, no webhook means size the interval to the actual stated update frequency — replaces a guessed number with a strategy grounded in how the specific content source actually behaves, which is the difference between a recommendation someone can defend in a design review and one that was picked because it was the number in the last tutorial anyone read. Tagging per content item rather than per collection is the detail that keeps on-demand revalidation useful at any real scale: a single global products tag means updating one item's price invalidates every cached product page on the site simultaneously, which technically satisfies "on-demand" but defeats the actual purpose of caching by forcing a full recompute across unrelated pages every time any one item changes. Separating pricing and stock — the fields where staleness has a real, quantifiable cost — from descriptions and images, which can tolerate a long cache window, is what stops the recommendation from collapsing into an all-or-nothing choice for the entire page: caching the whole product page uniformly under one setting means either the price is sometimes wrong, or the rarely-changing description gets refetched as often as the price does, and naming the split explicitly is what lets each field get the caching behavior it actually needs rather than settling for whichever compromise setting hurts the least.
What you get back
Recommendation: split by field. Stock and price stay uncached (cache: 'no-store' on that specific fetch), since the traffic pattern concentrates on best-sellers where a stale price is a real, visible cost. Descriptions and images use on-demand revalidation via revalidateTag('product-' + slug), fired from a Route Handler the product.updated webhook hits — tagged per product, not one 'products' tag for the whole catalog, so updating one listing's description doesn't force a recompute of the other 199 best-sellers. Fallback revalidate: 3600 stays as a safety net in case a webhook call is ever missed, not as the primary freshness mechanism.
Verified against
Claude Code Sonnet 4.6 · 2026-07-27
Cursor Cursor 2.1 · 2026-08-01
Changelog
- 2026-07-27 — Initial publish, verified against Claude Code (Sonnet 4.6) and Cursor 2.1 on a Next.js 16 commerce catalog with per-item revalidateTag.
Need this built into your business?
If a prompt isn't enough — custom software, built and maintained for you — that's Scult's day job.
EXPLORE CUSTOM SOFTWARE
