Why a page in Next.js is static by default?
Answered
Greater Pewee posted this in #help-forum
Greater PeweeOP
Hello everyone, i'm very confused about the static pages in Next.js. Why a Next.js page is static by default if data cache is not cached by default? It's very confusing in the documentation.
Answered by Brown bear
No worries! Basically, there's 3 cases:
1. You use some dynamic APIs (cookies, headers, etc) or explicitly opt out of static rendering. In this case, it will render when requested at runtime
2. You don't use dynamic APIs, you don't specify a revalidation time, and you don't invalidate the path ever. In this case, it will render at build time.
3. You don't use dynamic APIs, but you DO invalidate paths. In this case, it will rerender when invalid (i.e, past the revaidation time, or manullly invalidated)
1. You use some dynamic APIs (cookies, headers, etc) or explicitly opt out of static rendering. In this case, it will render when requested at runtime
2. You don't use dynamic APIs, you don't specify a revalidation time, and you don't invalidate the path ever. In this case, it will render at build time.
3. You don't use dynamic APIs, but you DO invalidate paths. In this case, it will rerender when invalid (i.e, past the revaidation time, or manullly invalidated)
29 Replies
Greater PeweeOP
The documentation says: If a route has a fetch request that is not cached, this will opt the route out of the Full Route Cache. The data for the specific fetch request will be fetched for every incoming request.
Brown bear
Routes being cached by default just means that Next will prefer to render a route statically if it can, but will render it dynamically if it uses dynamic apis or uncached data.
Greater PeweeOP
Oh, i think i get it. So by default (without using any api requests) is static, but if i use any fetch requests that are no cached, it will be dynamic?
Brown bear
Yes; if you use a fetch that explicitly opts out of caching, or if you use any dynamic APIs (cookies, headers, etc) it will be dynamic.
However, for performance purposes, you often do want to cache a route because non-logged-in users would all see the same page, and a short length cache may be helpful so you don't make the same async fetch 5000 times in one minute.
However, for performance purposes, you often do want to cache a route because non-logged-in users would all see the same page, and a short length cache may be helpful so you don't make the same async fetch 5000 times in one minute.
This is where ISR comes in, and you have static routes that get rerendered during runtime when they become invalid https://nextjs.org/docs/app/building-your-application/data-fetching/incremental-static-regeneration
Greater PeweeOP
So, if i use a fetch that don't explicitly opts out of caching, it will be static? That's the most confusing fact hahah
Brown bear
It's static, as in it's pre-rendered. However, with ISR that static path can be re-rendered at runtime, either because of a time-based cache invalidation, because you manually invalidate it, or because it didn't exist at build time.
Siamese Crocodile
What is ISR?
Brown bear
Incremental Static Regeneration
Siamese Crocodile
I've finished the course, but I think I've never heard about it. Could you explain briefly?
Brown bear
Taken from the ISR docs, this blog route will be prerendered statically for all blog posts that exist at compile time. Then, after 60 seconds, that static route becomes stale. The next person who visits it will get the stale one, but will trigger a re-render of the static page. After it's rerendered, the pre-rendered version will be replaced with the new one. And for any blog posts that didn't exist at build time, they will be rendered when they are first requested and then stored statically just like all the others.
app/blog/[id]/page.tsx
interface Post {
id: string
title: string
content: string
}
// Next.js will invalidate the cache when a
// request comes in, at most once every 60 seconds.
export const revalidate = 60
// We'll prerender only the params from `generateStaticParams` at build time.
// If a request comes in for a path that hasn't been generated,
// Next.js will server-render the page on-demand.
export const dynamicParams = true // or false, to 404 on unknown paths
export async function generateStaticParams() {
const posts: Post[] = await fetch('https://api.vercel.app/blog').then((res) =>
res.json()
)
return posts.map((post) => ({
id: String(post.id),
}))
}
export default async function Page({ params }: { params: { id: string } }) {
const post: Post = await fetch(
`https://api.vercel.app/blog/${params.id}`
).then((res) => res.json())
return (
<main>
<h1>{post.title}</h1>
<p>{post.content}</p>
</main>
)
}
quoting the docs:
Here's how this example works:
1. During next build, all known blog posts are generated (there are 25 in this example)
2. All requests made to these pages (e.g. /blog/1) are cached and instantaneous
3. After 60 seconds has passed, the next request will still show the cached (stale) page
4. The cache is invalidated and a new version of the page begins generating in the background
5. Once generated successfully, Next.js will display and cache the updated page
6. If /blog/26 is requested, Next.js will generate and cache this page on-demand
Here's how this example works:
1. During next build, all known blog posts are generated (there are 25 in this example)
2. All requests made to these pages (e.g. /blog/1) are cached and instantaneous
3. After 60 seconds has passed, the next request will still show the cached (stale) page
4. The cache is invalidated and a new version of the page begins generating in the background
5. Once generated successfully, Next.js will display and cache the updated page
6. If /blog/26 is requested, Next.js will generate and cache this page on-demand
The point of this, as opposed to dynamic routes, is you cache the rendered route for 60 seconds, meaning if 5000 people visit the /blog/1 at the same time, it won't kick off 5000 requests to your API. It'll only do 1, and then cache the result for 60 seconds.
Siamese Crocodile
Wow, powerful framework.
Brown bear
Indeed!
In addition to time based revalidation, you can manually invalidate a route. That would be useful if you for example, have CMS content maintained by editors, and you wanted to invalidate a blog post the moment they update the content. That way, the cached post would be served until you notified the server "Hey, that post needs to be rerendered".
@Brown bear It's static, as in it's pre-rendered. However, with ISR that static path can be re-rendered at runtime, either because of a time-based cache invalidation, because you manually invalidate it, or because it didn't exist at build time.
Greater PeweeOP
I think i understood now. The page is pre-rendered during build time (static), but it will be invalidated (ISR) if any user try to access the route?
Brown bear
Yes, but only if the cached route is invalid for some reason, i.e, the revalidation time is up or it was explicitly invalidated by some other code (i.e, server action calling
revalidatePath
).@Brown bear Yes, but only if the cached route is invalid for some reason, i.e, the revalidation time is up or it was explicitly invalidated by some other code (i.e, server action calling `revalidatePath`).
Siamese Crocodile
How long have you been using Next.js?
Brown bear
only about a couple months, but I've been using react for a LONG time.
@Brown bear only about a couple months, but I've been using react for a LONG time.
Siamese Crocodile
Do you mind if I send you DM?
Brown bear
Sure!
I will deal with it hahaha, thanks
Brown bear
No worries! Basically, there's 3 cases:
1. You use some dynamic APIs (cookies, headers, etc) or explicitly opt out of static rendering. In this case, it will render when requested at runtime
2. You don't use dynamic APIs, you don't specify a revalidation time, and you don't invalidate the path ever. In this case, it will render at build time.
3. You don't use dynamic APIs, but you DO invalidate paths. In this case, it will rerender when invalid (i.e, past the revaidation time, or manullly invalidated)
1. You use some dynamic APIs (cookies, headers, etc) or explicitly opt out of static rendering. In this case, it will render when requested at runtime
2. You don't use dynamic APIs, you don't specify a revalidation time, and you don't invalidate the path ever. In this case, it will render at build time.
3. You don't use dynamic APIs, but you DO invalidate paths. In this case, it will rerender when invalid (i.e, past the revaidation time, or manullly invalidated)
Answer
Brown bear
And the reason for all of this: performance gains.
Greater PeweeOP
Awesome!
I will save this message hahah
Thank you!