I recently had a surprising experience while testing ISR (Incremental Static Regeneration), a fascinating feature offered by Next.js.

In a nutshell, ISR allows us to statically generate a website at build time, meaning all the data is fetched initially and Next.js serves the cached version. However, we can also configure a Next.js page to revalidate itself at specified intervals.

To implement revalidation, we simply set the revalidate value in our Next.js 13 app folder, like so:

export const revalidate = 30

This line of code instructs the page to revalidate every 30 seconds.

After the revalidation period, the page is served super fast to the first visitor who hits the URL. However, in the background, the page is rebuilt with any necessary data fetching.

This functionality is really cool, but I stumbled upon a gotcha when using Vercel. On Vercel, the revalidation process runs in a serverless function.

I spent several hours troubleshooting what I believed was a bug in the new app folder (which is still in beta), but either I didn’t consult the proper documentation or the documentation was lacking.

The revalidation serverless function runs in a different environment than the initial build. While the initial build can write to the filesystem, the revalidation serverless function cannot. It can only write to the system tmp folder, which is accessed using os.tmpdir() (remember to import os from 'os').

There is no “communication” between the revalidation serverless function and the initial build. This limitation prevented me from downloading and incorporating images into the site.

Furthermore, I couldn’t access the previously downloaded files from the original build because they were in a completely separate environment.

This is likely common knowledge in a serverless function environment, but it caught me by surprise.

Once I discovered this limitation, I was able to find workarounds. For example, I could host the assets on S3 or, as a quick solution, encode small images as data URIs.

Here’s a useful tip: to debug revalidation, I utilized on-demand revalidation, which is a fantastic feature. On-demand revalidation allowed me to hit an API endpoint to revalidate a specific page route without waiting for the revalidation time to elapse.

However, I encountered a gotcha while using on-demand revalidation. I had enabled revalidation on a static route that didn’t fetch data (I had removed all the data fetching for debugging purposes). When I attempted to use on-demand revalidation, I encountered an issue stating that revalidation could not be performed because there was no data to revalidate. Essentially, it was marked as a server error, but it wasn’t actually an error. This may be a bug that will be resolved in future updates. Be mindful of the date of this post.

To summarize, revalidation and ISR on Vercel are powerful tools with some unexpected limitations. Understanding these limitations will help you navigate and find suitable solutions.