ProNextJS
    Professional Next.js Course
    Loading price
    30-Day Money-Back Guarantee
    lesson

    Automatic and Manual Revalidation

    Jack HerringtonJack Herrington

    We have a static page that shows the current date and time, but it would be good to have it update automatically.

    Automatic Revalidation

    Let's make it update every 5 seconds.

    To do that, we export a revalidate constant, setting its value to 5:

    // inside app/page.tsx
    
    export const revalidate = 5
    
    export default function Home() { 
      ...
    

    Now our page will be regenerated every 5 seconds if there is an incoming request.

    You can test this in the browser by refreshing. You'll notice that the timestamp updates every 5 seconds.

    You can see this in the console as well:

    Refreshing in the console

    Manually Triggering Revalidation

    What if we want to trigger a revalidation manually instead of on a timer?

    First, disable the timed revalidation by commenting out the revalidate constant.

    Then we'll create a RevalidateHomeButton client component in the app directory:

    // inside app/RevalidateHomeButton.tsx
    
    "use client";
    import { Button } from "@/components/ui/button";
    
    export default function RevalidateHomeButton({
      onRevalidateHome,
    }: {
      onRevalidateHome: () => Promise<void>;
    }) {
      return (
        <Button onClick={async () => await onRevalidateHome()} className="mt-4">
          Revalidate Home
        </Button>
      );
    }
    

    The RevalidateHomeButton component will accept a server action onRevalidateHome as a prop that will be called when the button is clicked.

    We can then import the RevalidateHomeButton to the Home component:

    // inside app/page.tsx
    import RevalidateHomeButton from "./RevalidateHomeButton";
    

    Inside of the page.tsx file, we'll create the async onRevalidateHome function that will trigger the revalidation of the homepage. The "use server"; pragma is used to define it as a server action, and we use the revalidatePath() function to revalidate the root path (/):

    export default function Home() {
    
      async function onRevalidateHome() {
        "use server";
        revalidatePath("/");
      }
    
      console.log(`Rendering / ${new Date().toLocaleTimeString()}`);
      return (
        <main>
          <div>{new Date().toLocaleTimeString()}</div>
          <RevalidateHomeButton onRevalidateHome={onRevalidateHome} />
        </main>
      );
    }
    

    Now, if you go back to the browser and hit the "Revalidate Home" button, it will trigger a revalidation of the homepage.

    Remember, server actions is that they return promises. This means you need to make sure we're using await when calling onRevalidateHome inside of the RevalidateHomeButton component. Otherwise, the revalidation might not happen as expected.

    Next, we'll talk about how this full-route caching approach affects API routes.

    Transcript

    We've got our static page that gives us our date and time, but we do want that to update every once in a while. So let's say we wanted to update every five seconds or so. Is there a way that we can invalidate that static page every five seconds? Sure. We export a const, call it revalidate, and we say we want it to revalidate every five seconds.

    Hit save and try this out. Now we can see that we have rendered a static page. We can see that the route is defined as a static route. Let's go see what happens in the browser. So if I hit refresh a bunch of times, it'll stick at 903 and then at 908, it'll pop over And there we go, because five seconds after three is eight.

    And yeah, so every five seconds, if it gets a new request after the last time it revalidated, then it will generate a new page and send it out. And you can actually go see that in the console. We can see that at 03, it re-rendered, and at 08, it re-rendered. But let's say that we don't want to do that based on time. We want to actually say at some point that we want to revalidate.

    So let's go and comment that out, and we'll create a button in here that we can use to force the revalidation called the Revalidate Home button. It's going to be a client component because it's interactive and needs to be a client component in order to execute something on the browser. It's going to be given a server action called onRevalidateHome, and it's going to wrap that in the ShadCN button and call that on revalidate home when you hit the button. All right let's go bring that into our page and we'll put it in our JSX. So how do we actually revalidate home?

    How do we tell Next.js that the content of home is now invalid and needs to be rebuilt? We use revalidate path for that. That is one way to do it. So let's bring that in. And then we'll create a server action.

    To do that, I define an async function and they use the use server pragma and then I simply say that I want to revalidate the path of slash. Pass that on to our button and hit save. Now let's build and start again and once again slash is marked as static. If I go on my browser and I hit refresh, now I can hit refresh as many times as I want and I get the same exact state but when I hit Revalidate Home and now I get a new version of Home. Now one little thing that might trip you up when you do this is if you are in Revalidate Home, if you just do simpling like this, where you do On Revalidate Home, and you don't await it, it is a promise, then you won't get the revalidation behavior because you're not awaiting that promise.

    So you do have to make sure that over in your client code you always await server actions. Next up, let's talk about how this full route cache affects API routes because it affects those as well.