Skip to main content
Last Reviewed: 2026-04-13

WordPress cache integration for Next.js 15

Use the Pantheon cache handler to enable automatic edge cache clearing when WordPress content changes


This guide shows you how to integrate WordPress cache invalidation with a Next.js 15 site on Pantheon. When you publish or update a post in WordPress, a webhook fires and tells Next.js exactly which cached data to refresh — no full rebuild required.

Learning objectives

This tutorial walks you through:

  • Setting up @pantheon-systems/nextjs-cache-handler in a Next.js 15 project
  • Tagging WordPress data with surrogate keys using fetch() cache tags
  • Creating a revalidation API endpoint that accepts WordPress webhook requests
  • Connecting a WordPress mu-plugin that sends webhooks when content changes
  • Configuring shared secrets on both sites via Terminus Secrets Manager
Information:
Next.js 15 and 16

This approach works for both Next.js 15 and Next.js 16. The cache handler extracts tags from the internal x-next-cache-tags header on cached page data regardless of version. You do not need to define Surrogate-Key headers in next.config.mjs.

For Next.js 16-specific features like 'use cache' and cacheTag(), see WordPress on-demand revalidation for Next.js 16.

Requirements

  • A Next.js 15 site on Pantheon (Quick start)
  • A WordPress site on Pantheon
  • @pantheon-systems/nextjs-cache-handler version 0.7.0 or later
  • Install the following:

* Requires logging in after installation.

Quick start with test upstreams

If you want to skip the manual setup and get a working site immediately, create a Pantheon site from one of the test upstreams that have WordPress cache invalidation pre-configured:

UpstreamNext.js VersionCache Strategy
nextjs_15_cache_starter15ISR + fetch tags — cache handler extracts tags automatically
nextjs_16_cache_starter16'use cache' + cacheTag() — cache handler extracts tags automatically

These are not core upstreams and are not shown by default in terminus upstream:list. Use the --all flag to find them:

These upstreams include the @pantheon-systems/nextjs-cache-handler package, WordPress REST API integration, surrogate key tagging, and a secured revalidation endpoint. To get end-to-end cache invalidation working:

  1. Create a site from the upstream.
  2. Set WORDPRESS_API_URL to your WordPress site's REST API base URL.
  3. Set a shared WEBHOOK_SECRET on both the Next.js and WordPress sites.
  4. Install the WordPress mu-plugin on your WordPress site.
  5. Install the Pantheon Advanced Page Cache plugin on WordPress so that WordPress' CDN caches are cleared appropriately.

The rest of this guide walks through the setup in detail.

How it works

When you tag your fetch() calls with surrogate keys (e.g., post-list, post-123), the @pantheon-systems/nextjs-cache-handler automatically tracks which tags are associated with which pages. When WordPress content changes and revalidateTag() is called, the cache handler clears the affected pages from Pantheon's edge CDN.

No Surrogate-Key headers in next.config.mjs are needed.

Install the cache handler

Configure Next.js

Create a cache-handler.mjs file in your project root:

Reference it in next.config.mjs:

No headers config is needed. The cache handler extracts tags automatically.

Add fetch tags to your data fetching

Tag your fetch() calls with surrogate keys that match what your WordPress mu-plugin sends:

The tags you pass to fetch() via next: { tags: [...] } are automatically propagated by Next.js to the page-level cache. The cache handler extracts them and maps them to the page's URL path.

Create the revalidation endpoint

Create an API route that receives WordPress webhook requests and calls revalidateTag():

When revalidateTag('post-list') is called, the cache handler:

  1. Looks up the tag mapping: post-list → ["/blogs", "/blogs/my-post"]
  2. Deletes the cached page entries for those paths
  3. Calls the edge CDN to purge /blogs and /blogs/my-post

Connect WordPress webhooks

You need:

  1. A WordPress mu-plugin that sends webhooks when content changes. See Add the WordPress mu-plugin.

  2. Shared secrets configured on both sites. See Configure secrets.

The surrogate key patterns (post-{id}, post-{slug}, post-list, term-{id}) must match between the WordPress mu-plugin and your fetch() tag values.

Differences from Next.js 16

FeatureNext.js 15Next.js 16
Cache tags set viafetch() with next: { tags }cacheTag() in 'use cache' functions
Tags on page cachePropagated from fetch tagsExplicitly set via cacheTag()
Cache handler configcacheHandler onlycacheHandler + cacheHandlers.default
revalidateTag() args1 arg: revalidateTag(tag)2 args: revalidateTag(tag, { expire: 0 })
Tag granularityTags from fetch callsAll cacheTag() values (more granular)

Both versions use the same cache handler tag extraction mechanism. The main difference is that Next.js 16's cacheTag() gives more granular control over which tags are associated with each page.

Next steps