ISR fallback and App Shell upgrade

generateStaticParams here returns only two of the four regions, and only one station within each. Everything else is an unlisted param, which is the case under test.

For an unlisted URL, Next.js serves the route's App Shell immediately, streams the real content, and then re-renders the page in the background with the now-known params. The next visitor to that same URL gets the upgraded result from cache. This is the Cache Components equivalent of fallback: true.

What to check

Listed. Click a prerendered link. It is fully rendered, with no fallback and stamps dated to the build.

Unlisted, first visit. Click an unlisted link. The region header and station panel arrive as fallbacks first, then stream in.

Unlisted, second visit. Go back and click the same link again. Now it comes from the background upgrade, with no fallback.

Count the fallbacks with curl.

# both params known: no fallbacks, ever
curl -s localhost:3000/isr-fallback/europe/london | grep -o 'data-fallback="[^"]*"' | sort -u

# known region, unlisted station: partial shell, only the station falls back
curl -s localhost:3000/isr-fallback/europe/paris | grep -o 'data-fallback="[^"]*"' | sort -u

# neither known: generic shell, both stream
curl -s localhost:3000/isr-fallback/africa/nairobi | grep -o 'data-fallback="[^"]*"' | sort -u

# then run either unlisted one again: no fallbacks, it upgraded

Prefetching counts as the first visit. In a build, just scrolling an unlisted link into view starts the upgrade before you click, so the click often lands on the upgraded result. To see the cold path, use curl or type the URL.

Prerendered at build time

These param values came from generateStaticParams (europe, asia-pacific), so they are complete static pages.

Not prerendered

No build-time params. First visit gets the App Shell; the upgrade happens behind it.

Deep links and the partial shell

Within a prerendered region, only the first station is prerendered. The rest reach the station page with an unlisted [station] param but a known [region], so their shell already has the region header filled in and only the station streams.