Two things all fast websites have:
1. Fast initial page load
2. Fast transitions between pages
There's two concepts you need to understand for this:
1. Prerendering
2. Prefetching
I’ll briefly explain both and how Next.js handles them under the hood.
Prerendering
To have a consistently fast initial page load, ideally you do some work ahead of time. If you need to create the page from scratch on every request, it is more likely some users will have a slow experience.
Prerendering is where you take the inputs to your page (like a CMS or a database) and produce an output that can be cached. Data in, HTML out.
Critically, this work happens *before* the user makes a request. You might have heard this called SSG (Static Site Generation). You can prerender all of the pages for your site. Then, take the outputs and put them behind a CDN. Consistent, predictable, fast initial page loads.
But what happens when your content changes? For a simple website, you might just regenerate all of the pages again from scratch. For slightly larger websites, you can selectively update a *single page* in the background.
This is called ISR (Incremental Static Regeneration). But the acronym isn't the important part. It's still prerendering — it's just happening in the background.
Bonus: What if most of the page can be prerendered, but there's one section which shows content that is unique to the visitor? Can you combine prerendering *and* fresh user data? This is called PPR (Partial Prerendering), and is an experimental feature of Next.js.
Prefetching
Let's say you have a web application with 100 pages. When navigating between different pages, you want it to feel instant.
At some point, you need to load the data for the next page. There’s no getting around that. The question then becomes — when does the new page load?
You know how mobile apps can feel really fast moving between tabs? Well, that's because you had to watch the App Store loading spinner while downloading a gigantic blob of code to your phone. You paid the cost upfront.
Similarly on the web, you can pay the cost upfront. Bundle all of the code into a JavaScript file, and load it when you boot the app. This is the traditional SPA (Single-Page Application) approach.
Because you did the work ahead of time, subsequent navigations between pages are really fast. But, can we have both? Can we navigate quickly between pages *and* have a fast initial page load?
Next.js splits your application into smaller chunks of code, which load based on the page you are navigating to. Rather than downloading all the code at once, you load it incrementally.
Next.js also understands which pages you are likely going to navigate to, so it's able to *prefetch* the new page in the background. By the time you go to click the link, the new page has already been loaded. It's a magic trick.
You click and there's no browser loading spinner. Instead, the client quickly switches to the newly loaded page. This is nice because it scales as you add more pages in your application, without inversely affecting the initial page load time.
Next.js tries to do the right prefetching by default (more improvements coming here shortly...) and power users can tweak the knobs to do more/less prefetching based on their needs. You have the control between performance and resource consumption.
Summary
The web has many rendering acronyms to explain how pages can be created: SSR, CSR, SSG, ISR, PPR, and more.
But I've found it helpful to instead think about it as:
1. When is content being prerendered? Ahead of time? In the background? Or are we getting fresh data on every request?
2. When are we paying the cost to load the next page? Ahead of time? In the background? Or are we loading a new page from scratch on every request?
I'm still workshopping this framing, so open to feedback.