High-cardinality sites can't pre-render every slug. Without generateStaticParams, every visit shows a Suspense fallback. With it, unknown slugs block while generating.
App Shell Upgrading gives unknown slugs an instant shell from CDN while dynamic data streams in. After the first visit, the shell self-upgrades to a fully static page. This behavior is always enabled with cacheComponents.
app/app-shell-upgrading/[slug]/page.tsx
1
'use cache';
2
3
export async functiongenerateStaticParams() {
4
return[{ slug:'1'}, { slug:'2'}, { slug:'3'}];
5
}
6
7
export default async functionPage({ params }){
8
const{slug}= awaitparams;
9
return<ProductDetailslug={slug}/>;
10
}
Demo
A product catalog with 9 products. Only 3 are in generateStaticParams.
Build-time products (1–3) load instantly with no fallback.
Request-time products (4–9) get a unique slug suffix on page load (persisted in session). Click one to see the App Shell stream in, then click it again or refresh the page to see the upgraded static result. Use the Regenerate button to get a new suffix and test with fresh slugs.
An artificial 2 second delay makes the difference more noticeable.
Notes
App Shell Upgrading requires experimental.appShells in next.config.ts. Combine 'use cache' with generateStaticParams and a loading.tsx to get a self-upgrading shell for unknown slugs.
This page was rendered with a 2 second artificial delay. If this product was pre-rendered, it loaded instantly. If it was runtime-discovered, an App Shell was streamed instantly while the data loaded in the background.