Incremental Static Regeneration (ISR)
Developer preview
Developer Preview
This page documents the developer preview of the SDK, version 20.81.1-alpha.25.sha-f076f9b857. In this version, each published route has one cached page for all visitors. The stable SDK made one page for each combination of personalization and test variants.
Static generation (ISR)#
The middleware rewrites each request to /uniform/[code]. The code identifies the route, not the visitor. Thus Next.js can cache one page for each route, and serve it to all visitors. Personalizations and A/B tests get their variants in the browser or at the edge. Refer to Personalization and A/B tests.
The code contains these values. A different value makes a different code, and thus a different cached page:
- The route path, with the query strings that you list in
queryStrings - The
keysfromrewriteRequestPath - The composition state: published, draft or editor
- The preview mode
- The default consent
- The locale and the release
- The edge mode flag
Draft and editor requests render on each request. Next.js does not cache them.
Render on the first visit (recommended)#
Return an empty array from generateStaticParams. The build prerenders no pages. Next.js renders each page on its first visit, and serves it from the cache after that:
app/uniform/[code]/page.tsx
This is enough for most sites. Only the first visitor of each page waits for the render.
warning
With Cache Components (cacheComponents: true), Next.js does not accept an empty generateStaticParams, and the build fails. Return at least one code. Refer to the Next.js message about empty generateStaticParams.
Prerender some paths#
To make the first visit fast, prerender the most important pages at build time with createUniformStaticParams. Next.js still renders the other pages on their first visit, because dynamicParams is true by default.
app/uniform/[code]/page.tsx
createUniformStaticParams does these steps for each path:
- It applies the
rewritefunction, if you give one. - It gets the published route from the Uniform Route API. A path that has no composition gives no code.
- It makes one code for each
defaultConsentvalue and eachedgeModevalue.
The build time grows with the number of paths, not with the number of variants.
warning
Put the paths of the visitors in paths, for example /about. Do not put internal code paths, for example /uniform/3~64~L2Fib3V0~~3.
Consent and edge mode values#
A prebuilt page is used only when its code is the same as the code from the middleware. Two values in the code depend on your middleware:
| Option | Default | Set it when |
|---|---|---|
edgeMode | false | You use an edge middleware. With vercelUniformEdgeMiddleware, use [true, false], because the default filter skips pages that have no placements. With your own filter, give the same filter. |
defaultConsent | The value of the server configuration | The middleware sets defaultConsent for each request. List each value that it can write, for example [true, false]. |
app/uniform/[code]/page.tsx
This example makes a maximum of 4 codes for each path.
Paths from the project map#
Get the paths from the Uniform project map, so the build includes new pages without a code change:
app/uniform/[code]/page.tsx
To prerender only the top-level pages, filter the paths:
For a full example, refer to the Component Starter Kit.
Localized paths#
Put each locale and path in paths. For examples, refer to Localize your app.
Path rewrites#
If the middleware changes the path with rewriteRequestPath, give the same change to createUniformStaticParams. The codes are then the same as the codes from the middleware:
note
keys from rewriteRequestPath go into the code. If your middleware adds keys from the request, for example from a query string, the build cannot know them. Do not prerender these paths.
Playground route#
createUniformPlaygroundStaticParams makes the codes for the playground route. It uses only the first path of paths, and makes one code for each defaultConsent value. Playground requests are draft requests, so most apps do not need to prerender them.
On-demand revalidation with webhooks#
When an author publishes content, Uniform sends a webhook to your app. The POST handler in app/api/preview/route.ts revalidates the cache tags and paths of the changed content. The next request gets the old page, and starts a new render in the background. The requests after that get the new page.
Step 1: Add the POST handler#
app/api/preview/route.ts
Step 2: Set the secrets#
Set UNIFORM_PREVIEW_SECRET, UNIFORM_WEBHOOK_SECRET, or the two variables, in your host:
You can make a strong secret with openssl rand -base64 32.
Step 3: Configure the webhook in Uniform#
- In Uniform, go to Settings > Webhooks.
- Add a webhook with the URL
https://your-site.com/api/preview?secret=your-secret-value. - Select these events:
composition.publishedandcomposition.deletedentry.publishedandentry.deletedprojectmap.node.insert,projectmap.node.updateandprojectmap.node.deleteredirect.insert,redirect.updateandredirect.deletemanifest.published
- Save the webhook.
For the tags that each event revalidates, and for the security checks, refer to Caching.
warning
The secret is a query string (?secret=…), not a header. The value in the URL must be the same as UNIFORM_PREVIEW_SECRET.
Verify the setup#
- Publish a change to a composition.
- Look for a
POSTrequest to/api/previewin the server log. - Make sure that the response body is
{ "handled": true, "tags": [...], "paths": [...] }. - Open the page two times. The second request shows the new content.
To do a test locally, use a tunnel service, for example ngrok or cloudflared. Set the webhook URL to the tunnel URL.
Host support#
On-demand revalidation must have a host that supports Next.js cache revalidation:
| Host | Support |
|---|---|
| Vercel | Supported, also revalidateTag |
| Self-hosted | Supported with the Next.js standalone output and a persistent cache folder |
| Netlify | Supported with the Netlify Next.js runtime |
| Cloudflare | Supported with the OpenNext adapter |
Read the documentation of your host to make sure that it supports on-demand ISR.
Manual revalidation#
To revalidate a page manually, revalidate its cache tag. The cached page uses the fetch tags of its route, so the tag expires the page too:
Do not use revalidatePath with the path of the visitor. The middleware rewrites the request to /uniform/[code], and with a rewrite, revalidatePath must get the destination route. Refer to revalidatePath with rewrites. To revalidate all Uniform pages, use revalidatePath("/uniform/[code]", "page").