SSG hosted on vercel that only revalidates on rebuild
Answered
Rock Dove posted this in #help-forum
Rock DoveOP
Hi all,
I'm using nextjs 14 + vercel to host a website using strapi as a CMS. Strapi uses a webhook to trigger redeploy when content changes, thus most of the SSG results can be cached forever, until the next build.
However, I'm seeing a few issues:
1. If I set revalidate: false in the fetch options, the data cache will never revalidate, thus stale data will be used for subsequent builds
2. If I set a low revalidate (1) the cache control headers contain max-age 1, and the cache header implies it was a miss. It's not totally clear to me if it's rebuilding the route at that point or not, and it's unclear what impact this has with the CDN's ability to cache
Ideally I'd like to be able to set revalidate: false and just clear the data cache on each deploy, but the vercel api seems to only allow disabling the data cache, not purging it.
Additionally one component has data that needs to be refetched every hour, setting revalidate to 3600 for that fetch request seems to be working as intended.
Am I overthinking this? Basically I'd like the equivalent of a last-modified header, "cache this until it's been changed by a redeploy"...
I found [this github issue](https://github.com/vercel/next.js/issues/54452) but the proposed solution still results in max-age 1 and the undetermined caching / cdn behavior mentioned above
Thanks a bunch
I'm using nextjs 14 + vercel to host a website using strapi as a CMS. Strapi uses a webhook to trigger redeploy when content changes, thus most of the SSG results can be cached forever, until the next build.
However, I'm seeing a few issues:
1. If I set revalidate: false in the fetch options, the data cache will never revalidate, thus stale data will be used for subsequent builds
2. If I set a low revalidate (1) the cache control headers contain max-age 1, and the cache header implies it was a miss. It's not totally clear to me if it's rebuilding the route at that point or not, and it's unclear what impact this has with the CDN's ability to cache
Ideally I'd like to be able to set revalidate: false and just clear the data cache on each deploy, but the vercel api seems to only allow disabling the data cache, not purging it.
Additionally one component has data that needs to be refetched every hour, setting revalidate to 3600 for that fetch request seems to be working as intended.
Am I overthinking this? Basically I'd like the equivalent of a last-modified header, "cache this until it's been changed by a redeploy"...
I found [this github issue](https://github.com/vercel/next.js/issues/54452) but the proposed solution still results in max-age 1 and the undetermined caching / cdn behavior mentioned above
Thanks a bunch
Answered by Rock Dove
Ok, so I think I found a working solution (super hard to debug in vercel though, there seems to be no visibility into backend logs that aren't tied to a request for ISG).
The solution is not to use
This website in particular has two data sources: strapi (cms), which uses a deploy hook to rebuild the site when content changes, and a third party with no webhooks whose data we want to expire after 1 hour.
So, the solution is to use
Thus, an API was added to revalidate everything - essentially revalidatePath('/', 'layout') behind a secret.
The documentation can make it very confusing, not to mention it's hard to debug the cache headers generated on a deployed vercel site since they are stripped, but this seems to do the trick. It seems to me like the full route cache and data cache probably should be separate concerns, at least if you opt in to it. It's weird that I can't have a configuration that says "cache these routes forever, but get fresh data on the next build". Sure, you could build a static site, but there are benefits to ISG.
The solution is not to use
revalidate: 1 because with the app router, both the data cache and full route cache follow the same revalidation rules. So if a static page makes a fetch request with revalidate: 1, it will be generated on the next request > 1 second later. This is usually not what you want, especially if you're using deploy hooks to rebuild your site when data changes in your CMS.This website in particular has two data sources: strapi (cms), which uses a deploy hook to rebuild the site when content changes, and a third party with no webhooks whose data we want to expire after 1 hour.
So, the solution is to use
revalidate: false for the strapi content - cache it forever, while using revalidate: 3600 for the other data source. However, since the page router shares revalidation rules between the full route and data cache, and the data cache is persisted between builds... your next build will have stale data since the requests to strapi never revalidate.Thus, an API was added to revalidate everything - essentially revalidatePath('/', 'layout') behind a secret.
The documentation can make it very confusing, not to mention it's hard to debug the cache headers generated on a deployed vercel site since they are stripped, but this seems to do the trick. It seems to me like the full route cache and data cache probably should be separate concerns, at least if you opt in to it. It's weird that I can't have a configuration that says "cache these routes forever, but get fresh data on the next build". Sure, you could build a static site, but there are benefits to ISG.
1 Reply
Rock DoveOP
Ok, so I think I found a working solution (super hard to debug in vercel though, there seems to be no visibility into backend logs that aren't tied to a request for ISG).
The solution is not to use
This website in particular has two data sources: strapi (cms), which uses a deploy hook to rebuild the site when content changes, and a third party with no webhooks whose data we want to expire after 1 hour.
So, the solution is to use
Thus, an API was added to revalidate everything - essentially revalidatePath('/', 'layout') behind a secret.
The documentation can make it very confusing, not to mention it's hard to debug the cache headers generated on a deployed vercel site since they are stripped, but this seems to do the trick. It seems to me like the full route cache and data cache probably should be separate concerns, at least if you opt in to it. It's weird that I can't have a configuration that says "cache these routes forever, but get fresh data on the next build". Sure, you could build a static site, but there are benefits to ISG.
The solution is not to use
revalidate: 1 because with the app router, both the data cache and full route cache follow the same revalidation rules. So if a static page makes a fetch request with revalidate: 1, it will be generated on the next request > 1 second later. This is usually not what you want, especially if you're using deploy hooks to rebuild your site when data changes in your CMS.This website in particular has two data sources: strapi (cms), which uses a deploy hook to rebuild the site when content changes, and a third party with no webhooks whose data we want to expire after 1 hour.
So, the solution is to use
revalidate: false for the strapi content - cache it forever, while using revalidate: 3600 for the other data source. However, since the page router shares revalidation rules between the full route and data cache, and the data cache is persisted between builds... your next build will have stale data since the requests to strapi never revalidate.Thus, an API was added to revalidate everything - essentially revalidatePath('/', 'layout') behind a secret.
The documentation can make it very confusing, not to mention it's hard to debug the cache headers generated on a deployed vercel site since they are stripped, but this seems to do the trick. It seems to me like the full route cache and data cache probably should be separate concerns, at least if you opt in to it. It's weird that I can't have a configuration that says "cache these routes forever, but get fresh data on the next build". Sure, you could build a static site, but there are benefits to ISG.
Answer