Next.js ISR

Next.js ISR Manual Revalidation at Edge

CloudFront now natively supports the stale-while-revalidate cache-control header. But it does not support automatic manual revalidation for Next.js like you are used to on Vercel.

Flightcontrol has an option to add ISR manual revalidation support to CloudFront to get the same functionality as Vercel has.

See the Next.js docs (opens in a new tab) for more details on ISR.


This will override the native CloudFront stale-while-revalidate support and add support for manual revalidation from Next.js's built-in APIs.


  • When creating or editing an environment with a Fargate service, the Add Next.js ISR manual revalidation support to CloudFront check box will be located in the Miscellaneous section of the service configuration. Click the toggle to enable this feature.

    Next.js ISR check box


  • You can also add this feature in your flightcontrol.json file by adding a field in the fargate services config like the following:
    • "enableCloudfrontSwr": true

How Our ISR Implementation Works

  • When you request any file from your website, for example: ( This is a path that uses stale-while-validate caching policy.
  • As this is the first request ever, CloudFront checks its cache, and finds no matches, so it is considered a MISS, and instead of triggering the origin server immediately, it triggers our custom developed Lambda@Edge function.
  • This Lambda@Edge function does not find this path /isr in its dictionary, so it adds it, and asks for offline async fetch for this content.
    • As this is the first request, in order not to fail the request, the lambda function, will instruct CloudFront to relay the request to the origin server, and serve the content.
    • The offline async process, will retrieve the content one more time from the origin server, and caches a hash for the content, and its expiration time.
  • Now for the next 5 seconds, CloudFront will be serving the content from its own cache.
  • After the 5 seconds, CloudFront will trigger the Lambda@Edge function again, asking about the /isr path, this time the Lambda@Edge function is well prepared, and finds the path in its dictionary, and compares the hash of the content cached with CloudFront to the hash that we retrieved from the server, if match, Lambda@Edge instructs CloudFront to consider the content as valid, and serves the content from its cache (origin server is not triggered). This is considered a RefreshHit (i.e. the content is still the same, and CloudFront refreshes it from its own cache).
  • Once the content expires on the Lambda@Edge dictionary, it asks for a refresh offline async. And continue to serve the content cached with CloudFront.

What if the content actually changed?

  • If the content changed on the origin server, the offline async process, will determine the new hash.
  • This time, the Lambda@Edge function, determines that the hash for the cached content is different, so for the very first request it receives for this path, it asks CloudFront to refresh its content from the origin server.
  • In the meanwhile till CloudFront refreshes its content, the Lambda@Edge will ask CloudFront to serve the cached content for any subsequent requests (so the origin server is hit only once by CloudFront)