Summary:
I found that publishing new posts on Atlas did not work as expected. New posts did not appear immediately. I was told that this was normal and I had to wait for the revalidate timeout to happen. But this still wasn’t right. I did a deep dive into how Atlas does caching and revalidating. I found that:
- you can have a mix of fresh/stale content for a while after publishing new content
- it can take double the
revalidatetime to see the new content - different users may see different content depending on where they are in the world
Atlas and Incremental Static Regeneration (ISR)
There are three different kinds of server-side content generation in Next:
- Static Site Generation (SSG) – this builds the whole site from nothing. It is slow but comprehensive and ends up with cached, static content. Rebuilds are needed whenever content changes.
- Server-side Rendering (SSR) – this builds a page each time Next gets a request. It’s like PHP. It keeps content dynamic – no rebuilds necessary. But is slower to server requests and loads the Node server. You can help this by putting caching in front of Next.
- Incremental Static Regeneration (ISR) – this builds and serves static pages, but it does them one at a time and clears the cache (regenerates/revalidates) according to some rule.
There are two kinds of ISR in Next.
“On-demand” ISR is when the Next server is notified when there is a content change so that it can re-build. This seems to be what doesn’t work fully in Atlas. WP Engine are working on this. This limitation is documented in the Framework Guides sections of the Atlas docs.
While our Node infrastructure will support path-based revalidation on-demand, this revalidation will currently not extend to edge cached versions of that path, nor will they apply to all instances of your front-end application (if scaled beyond a single instance). This is under active investigation by our engineering team.
“Path-based ISR“: I think this is what “Non-on-demand” ISR is called . This is where the revalidate setting comes in. By default Atlas/Faust (not sure which) has a revalidate setting of 900 seconds or 15 minutes.
When the revalidate timeout is reached, Next will serve the old page and trigger a refresh of the content in the background, so that the new content is served next time.
Cloudflare and Next both cache content
Atlas puts Cloudflare in front of Next, and the revalidate timeout is also used as the cache timeout in Cloudflare.
Cloudflare’s cache has to expire to trigger a revalidate in Next.
So here’s what happens when you change the content in an Atlas site with a 15 minute revalidate.
- (Mins:Secs – times are examples and may vary)
- 00:00 – Content is changed in WordPress. Cached content in Next is not changed. Cached content in Cloudflare is NOT changed.
- (no later than) 15:00 – Cloudflare cache expires
- 15:10 – Page is hit. Cloudflare refreshes content. This hits Next. Next serves the old page to Cloudflare, which caches it. Next triggers a refresh in the background. User sees old page
- 15:20 – Page is hit. Next has the new page now, but Cloudflare still has the old page. User sees old page
- 30:10 – Cloudflare cache expires again.
- 30:20 – Page is hit. Cloudflare refreshes content. This hits Next again. Next now serves the new page, and triggers another refresh as its revalidate timeout has expired again as well. User sees new page.
In short, with this setup, it can take up to two Cloudflare CDN expiries to see the new content!! On a low-traffic site (such as a developer like me testing Atlas out by themselves) this is going to tend towards the 2 x the revalidate time.
This is complicated by the fact that the CDN has multiple caches in different “Edge” locations. And, on a busy site, Atlas can spin up multiple instances of Node/Next. So you can have a mix of old and new content served from different places for some time after the revalidate timeout.
Cache clearing
It’s worth noting that there are a couple of ways to refresh the content.
Rebuild / Clean Rebuild in the WPE Portal

These options rebuild the Next app from the sources in Git. From what I can tell the “Clean rebuild” option is the one that also does a full rebuild of the site content. Though the current descriptions of these options are not clear to me.
Purge cache

This option clears the CDN/Cloudflare caches, but does not clear the Next cache. So, oddly, this will not show fresh content. But it will (on the next page visit) trigger an ISR of pages in Next. So new content won’t appear immediately, but it will appear sooner than if you hadn’t done the cache purge.
I guess this will also purge the asset cache of images, CSS, JS, etc.
Tracing / Debugging with headers in dev tools.
Now that we know a bit about how this works, we can use the HTTP response headers to check our understanding and do diagnosis. I’m not 100% on the details here, but I’ll give it my best go.
There are (at least) 4 relevant headers:
age– this is from Cloudflare and tells you how many seconds old the page iscache-control– this will have a value likes-maxage=900, stale-while-revalidateand the maxage should be the same as therevalidatesetting for the page in Nextcf-cache-status– the Cloudflare cache status – should beHITorEXPIREDx-nextjs-cache– the Next cache status – this should beSTALEorHIT, but note that this is not the current state of the Next cache, but rather the cached state stored in Cloudflare. So you can seeSTALEhere for a while when you would normally only seeSTALEoccasionally with ISR, on those hits that trigger a revalidate
Let’s follow the steps through with a site using the Atlas Portfolio Blueprint.
1. Make a new post in WordPress

2. Open Dev Tools and reload the home page of the site
This disables browser caching and lets us see network requests. The new post doesn’t show in the “Latest posts”.
Both the Next AND Cloudflare caches are hit and we get old content.
If we select the main HTTP request and view the response headers we can see this.

3. Clear the Cloudflare cache and try again
Use the “Purge cache” button in the WP Engine Portal to clear the Cloudflare cache.
Reloading the homepage should show the cf-cache-status has expired. In the screenshot below this has happened BUT, the Next cache is still showing us a HIT so we’ve not hit the revalidation time in Next yet.

4. Clear the Cloudflare cache and try again
We’ll need to wait a while longer and repeat the Purge cache -> Reload the page cycle until we see both caches have expired:

We still don’t see the new content. This has triggered the refresh in Next, but Next served the old page to Cloudflare. Cloudflare will cache this for another 900 seconds and serves it to us.
5. (You guessed it…) Clear the Cloudflare cache and try again
Do another Purge cache to clear out Cloudflare, and then reload.
Cloudflare will now get the NEW page from Next…

We see the new post. Hooray! And the expired Cloudflare response, but the HIT in Next.
We got there – and the headers showed us what was going on.
Thoughts
This seems over-engineered.
Cloudflare is great because it takes the static content from Next and caches it at the edge, close to users. It keeps the load on the Atlas node server(s) low because Atlas only gets requests for cache misses in Cloudflare.
But I don’t understand why, if we are doing this, we also need ISR.
It seems to me like we may as well just use Next for SSR and generate pages dynamically. At least for “marketing” sites that are effectively static HTML content. (For dynamic sites like eCommerce I suspect there are ways to do fragment caching in Next and this is probably a good leverage of ISR.)
At the very least we could turn the revalidate in Next right down to 10 second or something to quickly serve a static pages for Cloudflare’s requests, and to regenerate in the back end more frequently to keep content fresh. However, from what I understand this config also controls the cache timeout in Cloudflare, so we’d need to find a way to override this in Cloudflare, or otherwise disconnect the sync between these values.
I appreciate there are trade offs here, I’m not an expert in the platform, and there are probably excellent reasons why things are like they are.
Links / Resources
Some things I found along the way:
- WP Engine Headless/Atlas support page
- Atlas Platform developer docs
- Faust.js framework guide for Atlas – includes statement on ISR compatibility
- There is an Atlas CLI tool!
- Next.js docs on Incremental Static Regeneration (ISR)