Confusion about SSG and SSR in Next 14
Answered
Black Caiman posted this in #help-forum
Black CaimanOP
Hey guys, I'm confused about how Next.js generates static routes.
I'll tell you what I want to do. I was migrating a Pages Router project I made. In that project, I had dynamic routes, and routes /1 and /2 were converted to Static Site Generation. The rest were rendered using Server Side Rendering as the user clicked on a link.
Now in Next 14, I'm trying to do the same thing, but when I check the network section in the devtools, I realize it fetches all the routes. Which seems strange to me, considering that routes 1 and 2 should return an HTML file, and the rest of the routes should fetch when the user clicks on that route. I'm attaching photos so you can see it. I'm not sure if I'm confused about how Next works now with React Server Components.
https://nextjs.org/docs/14/app/api-reference/functions/generate-static-params#single-dynamic-segment
https://nextjs.org/docs/14/app/building-your-application/routing/dynamic-routes#generating-static-params
I'll tell you what I want to do. I was migrating a Pages Router project I made. In that project, I had dynamic routes, and routes /1 and /2 were converted to Static Site Generation. The rest were rendered using Server Side Rendering as the user clicked on a link.
Now in Next 14, I'm trying to do the same thing, but when I check the network section in the devtools, I realize it fetches all the routes. Which seems strange to me, considering that routes 1 and 2 should return an HTML file, and the rest of the routes should fetch when the user clicks on that route. I'm attaching photos so you can see it. I'm not sure if I'm confused about how Next works now with React Server Components.
https://nextjs.org/docs/14/app/api-reference/functions/generate-static-params#single-dynamic-segment
https://nextjs.org/docs/14/app/building-your-application/routing/dynamic-routes#generating-static-params
Answered by LuisLl
React Server Components do not necessarily return HTML. What they return is a React Server Components Payload (RSC Payload) which is basically a stringified version of your Component output rendered on the Server.
This RSC payload is basically React Virtual DOM that blends in with the existing React DOM when it reaches the client.
What Next.js actually does for you is go ahead and pre-render all this output into static HTML to send down as the initial load for a page. That RSC payload gets transformed into HTML on the server but those are two different processes.
SSR is separate from RSC, that’s why you can still pre-render client components on the server and send their initial state in the same first HTML response back from the server.
This RSC payload is basically React Virtual DOM that blends in with the existing React DOM when it reaches the client.
What Next.js actually does for you is go ahead and pre-render all this output into static HTML to send down as the initial load for a page. That RSC payload gets transformed into HTML on the server but those are two different processes.
SSR is separate from RSC, that’s why you can still pre-render client components on the server and send their initial state in the same first HTML response back from the server.
7 Replies
@Black Caiman Hey guys, I'm confused about how Next.js generates static routes.
I'll tell you what I want to do. I was migrating a Pages Router project I made. In that project, I had dynamic routes, and routes /1 and /2 were converted to Static Site Generation. The rest were rendered using Server Side Rendering as the user clicked on a link.
Now in Next 14, I'm trying to do the same thing, but when I check the network section in the devtools, I realize it fetches all the routes. Which seems strange to me, considering that routes 1 and 2 should return an HTML file, and the rest of the routes should fetch when the user clicks on that route. I'm attaching photos so you can see it. I'm not sure if I'm confused about how Next works now with React Server Components.
https://nextjs.org/docs/14/app/api-reference/functions/generate-static-params#single-dynamic-segment
https://nextjs.org/docs/14/app/building-your-application/routing/dynamic-routes#generating-static-params
Black CaimanOP
This is my actual code:
page.js
import Link from "next/link"
export async function getPokemones() {
const res = await fetch('https://pokeapi.co/api/v2/pokemon?limit=151')
const data = await res.json()
return data.results
}
const Pokemon = ({ pokemon }) => {
const id = pokemon.url.split('/').filter(x => x).pop()
return (
<li>
<Link href={`/pokemones/${id}`}>
{pokemon.name}
</Link>
</li>
)
}
export default async function Home() {
const pokemones = await getPokemones()
return (
<div>
<p data-testid='titulo'>Pokemones</p>
<ul>
{pokemones.map(pokemon => <Pokemon pokemon={pokemon} key={pokemon.name} />)}
</ul>
</div>
);
}
pokemones/[id]/page.js
import Link from "next/link"
export async function generateStaticParams() {
return [{ id: '1' }, { id: '2' }]
}
async function getPokemones(id) {
const res = await fetch(`https://pokeapi.co/api/v2/pokemon/${id}`)
const data = await res.json()
return data
}
export default async function Pokemon({ params: { id } }) {
const data = await getPokemones(id)
return (
<div>
<h1>{data.name} número #{data.id}</h1>
<picture>
<img
src={data.sprites.front_default}
alt={`Pokemon ${data.name}`}
width={400}
height={400} />
</picture>
<Link href='/'>Volver al inicio</Link>
</div>
)
}
You’re effectively creating 2 static pages at build time (id 1 and 2), and the rest will be dynamically generated when you request them, on demand. That’s what you expect, I believe.
What’s happening in your screenshot is that Next.js is prefetching all the
What’s happening in your screenshot is that Next.js is prefetching all the
<Link>
instances that appear in your viewport, basically requesting them earlier before you click on them, that’s the default behavior. If you don’t want this behavior, then turn off the prefetch off the <Pokemon>
component, specifically the <Link>
component it renders.@LuisLl You’re effectively creating 2 static pages at build time (id 1 and 2), and the rest will be dynamically generated when you *request them*, on demand. That’s what you expect, I believe.
What’s happening in your screenshot is that Next.js is *prefetching* all the `<Link>` instances that appear in your viewport, basically *requesting* them earlier before you click on them, that’s the default behavior. If you don’t want this behavior, then turn off the *prefetch* off the `<Pokemon>` component, specifically the `<Link>` component it renders.
Black CaimanOP
Okay, thank you very much. That clears up my doubts. Another question: Am I generating two routes, 1 and 2, statically? Why, when I log in and check the Network in Chrome's devtools, it only shows the Pokemon image? I thought, or from what I've seen, that these routes are generated statically and should return an HTML element that was already created when the app was built?
And the same with dynamic routes. I thought the SSR made the request to the server to generate the HTML and then returned an HTML that was rendered in the app, but from what I see, it only requests the image and renders the rest as a SPA.
This is a bit confusing because, reviewing the React documentation, Server Components return HTML, but I don't understand if they return HTML as a document or to inject it into the HTML of a React SPA page.
And the same with dynamic routes. I thought the SSR made the request to the server to generate the HTML and then returned an HTML that was rendered in the app, but from what I see, it only requests the image and renders the rest as a SPA.
This is a bit confusing because, reviewing the React documentation, Server Components return HTML, but I don't understand if they return HTML as a document or to inject it into the HTML of a React SPA page.
React Server Components do not necessarily return HTML. What they return is a React Server Components Payload (RSC Payload) which is basically a stringified version of your Component output rendered on the Server.
This RSC payload is basically React Virtual DOM that blends in with the existing React DOM when it reaches the client.
What Next.js actually does for you is go ahead and pre-render all this output into static HTML to send down as the initial load for a page. That RSC payload gets transformed into HTML on the server but those are two different processes.
SSR is separate from RSC, that’s why you can still pre-render client components on the server and send their initial state in the same first HTML response back from the server.
This RSC payload is basically React Virtual DOM that blends in with the existing React DOM when it reaches the client.
What Next.js actually does for you is go ahead and pre-render all this output into static HTML to send down as the initial load for a page. That RSC payload gets transformed into HTML on the server but those are two different processes.
SSR is separate from RSC, that’s why you can still pre-render client components on the server and send their initial state in the same first HTML response back from the server.
Answer
If you wanna see the actual output of the RSC payload you can find it in the “Elements” tag embedded as
<script>
tags, you’ll find the stringified output of your React tree rendered on the server, but after all this is just a soft of React Virtual DOM, a description of the UI.@LuisLl If you wanna see the actual output of the RSC payload you can find it in the “Elements” tag embedded as `<script>` tags, you’ll find the stringified output of your React tree rendered on the server, but after all this is just a soft of React Virtual DOM, a description of the UI.
Black CaimanOP
I understand. Thank you very much. These are concepts that seem quite complex to me, and I need to get used to them. Do you have any resources to delve deeper into them and understand how they work? Both in React and Next.js.
Yes, here’s this really good blogpost about React Server Components:
https://tonyalicea.dev/blog/understanding-react-server-components/
https://tonyalicea.dev/blog/understanding-react-server-components/