Note: In order to build the example code you will need to be running the time-api server
# from 01-next-caching run
cd ./time-api &&
pnpm install &&
pnpm dev
Let's explore the full route cache in the Next.js App Router.
As the name implies, it caches the entire route. We'll work with a basic Next.js application containing a single route. When refreshed, it displays a new time.
The Example App
Our application is a standard Next.js setup with shadcn and Tailwind for styling.
When we load the page, we see the current time displayed. The time updates with each refresh.
Here's the code for our page component:
// inside src/app/page.tsx
export default function Home() {
console.log(`Rendering / ${new Date().toLocaleTimeString()}`);
return (
<main>
<div>{new Date().toLocaleTimeString()}</div>
</main>
);
}
This code logs the current time to the console and also renders it within a div
element.
When running in development mode, hitting refresh updates the displayed time, generating a new console log entry with each refresh.
However, things behave differently in production mode.
After building the app with the next build
command and starting it in production mode (next start
), refreshing the page consistently displays the same time. This behavior stems from Next.js's ability to recognize and treat this route as static during the build process.
Static and Dynamic Routes
Next.js classifies routes as either static or dynamic. Our page, as it stands, is a static route. It doesn't involve elements that would necessitate re-rendering on the server for each request.
The build process generates static HTML for these routes, resulting in the same content served on each request. Static routes are great for performance, as they eliminate server roundtrips for unchanged content.
Conversely, dynamic routes require server-side rendering for every request.
Inspecting the route table generated after building a Next.js application can tell you if a route is static.
Here is our route table:
Notice the "O" next to the /
route. This "O" signifies a statically generated route. Static routes are optimal for performance, but there are times when you might want to force a route to render dynamically.
Forcing Dynamic Rendering
There are situations where you might want to force a route to render dynamically. Let's look at a couple of ways to achieve this.
Using unstable_noStore
One approach is to use the unstable_noStore
function from next/cache
. By invoking this function within our React server component, we signal to Next.js that the route should be treated as dynamic.
Here's how we incorporate it:
// inside app/page.tsx
import { unstable_noStore as noStore } from 'next/cache';
export default function Home() {
unstable_noStore();
console.log(`Rendering / ${new Date().toLocaleTimeString()}`);
...
After rebuilding and starting the application, we can see that the /
route is now marked with an "F", indicating it is a dynamic route:
Refreshing the page now generates a new time on each request. The unstable_noStore
function effectively prevents Next.js from statically generating the route.
The route table, generated during the build process, serves as the definitive guide for understanding how Next.js handles caching for your routes.
Other Ways to Force Dynamic Rendering
unstable_noStore
isn't the only way to indicate that a route is dynamic. Actions within the component that suggest dynamic behavior can also achieve this. For instance, accessing properties of the incoming request can signal to Next.js that the component needs dynamic rendering.
Can you think of methods to access the incoming request within a React server component?
We'll look at some in the next lesson.