Datasource-level "revalidateTag"
Get the project source code below, and follow along with the lesson material.
Download Project Source CodeTo set up the project on your local machine, please follow the directions provided in the README.md
file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.
This lesson preview is part of the Blazing Fast Next.js with React Server Components course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.
Get unlimited access to Blazing Fast Next.js with React Server Components, plus 70+ \newline books, guides and courses with the \newline Pro subscription.
[00:00 - 00:34] If you have understood what revalidatePath does, revalidateTag will be quite intuitive. So revalidatePath lets us invalidate a static render to compute a new render with up-to-date data, but on demand, if I take a very concrete example, when we create a new product on the administration interface, we revalidate the pathes that display the product so that when the user updates the page, on the next request, they will see the fresh list of products.
[00:35 - 00:54] But we have a problem, it's that we have to revalidate all the pages that display the product list. That's a bit annoying because that might change, maybe the products page will probably always list the products, but maybe the homepage will change and only display the flagship product and the link towards the rest of the products.
[00:55 - 01:09] Maybe we will show the products on other pages, marketing pages, I don't know. So it's weird because the way we get data, we get data in the component here and not at the page level.
[01:10 - 01:19] It's the ProductListAsync component that is calling the database with rscGetProducts. Okay, it's not a page, so it's weird to invalidate the page.
[01:20 - 01:31] Instead, we can use the revalidateTag API that I've commented here initially for the exact same purpose. So why a tag?
[01:32 - 01:55] A tag because the idea is that you need to put a label, a tag on the data you are querying to be later on able to say, oh, those data, they are stale, you need to run the database query to get up-to-date data. We are tagging the data, they do their lifecycle, they display in the website, and at some point we say this tag is outdated.
[01:56 - 02:04] Next time you get the data with this tag, you need to first update them, basically. That's what you are telling Next.js and React to do with revalidateTag.
[02:05 - 02:29] So instead of thinking in pages, we are more thinking in data sources and components. More broadly, there has been this general direction in the React and Next.js ecosystem to move the APIs that were only available at page level, like getStaticProps, getServerSideProps, if you have been a long time Next.js user, you might know about them, they were page-level.
[02:30 - 02:42] We move all those capabilities at component-level. And it's more powerful because now the product list can be reused anywhere and it's responsible of its own data and data lifecycle.
[02:43 - 02:56] It becomes the single source of truth and that's easier to reason about and maintain. Notice in this code that I'm doing a check on the "USE_UNSTABLE" environment variable.
[02:57 - 03:11] That's what we call the feature flag. The problem is that revalidateTag relies on feature that is at this time experimental and maybe unstable. The ability to tag the database call.
[03:12 - 03:22] This ability is not yet integrated officially into React so it's still unstable . If we check the corresponding data fetching method, let's get into the product list.
[03:23 - 03:54] We need to open our rscGetProducts function and we see that it's also using this feature flag "USE_UNSTABLE" and if it's true, it will use the "unstable_cache" and add the "tags" options. We have a value "productsTag" that is just a constant, a string constant to tag the call, because the official cache that is currently stable is not able to have tags.
[03:55 - 04:14] So we cannot tag it so we cannot revalidate the tag. So if I enable USE_UNSTABLE, I will be able to tag the getProducts call and therefore to revalidate it. Let's run an experiment. So I'm going to open my environment file .
[04:15 - 04:26] I'm going to set, okay, I'm going to create a local version. So to set the tag, I have to modify my local environment variable.
[04:27 - 04:52] I will set it to a truthy value "1". So now the condition here in createProduct to update the product list will use revalidateTag thanks to this condition. And then here the rscGetProducts will also use the unstable_cache and set up the tag that we later on, revalidate. So it should work.
[04:53 - 05:10] I need to stop my application, rebuild, give it a shot. And I get a beautiful error because I'm using a version of Next.js that as a small bug that prevents unstable_cache to be called at top-level.
[05:11 - 05:26] Basically, you cannot call, I don't know which one is faulty. If it's my getProducts, yeah, it seems that it's my getProducts that doesn't work because it's defined top-level. Basically, you cannot do that in the conversion that just a bug.
[05:27 - 05:36] So I need to update my Next.js version to Next 14. That's what we call unstable. Now I've updated the application to Next 14.
[05:37 - 06:37] And let's hope that it works. It seems to be building. Okay, and now my unstable_cache call seems to not fail at build time. Let me open the application and check that everything works okay. So I need to add yet, yet, yet another product, again, set the price, set the change, check the home page, and I see yet, yet, yet, yet, another product again. Okay, the code is strictly equivalent, revalidating the tag or revalidating the path for each concerned page is the same thing. The difference lies in the granularity where you reason. You can think about Next.js applications in terms of pages. And you can think about them in terms of components.
[06:38 - 08:42] So thinking about them in terms of components is more "exact" in the sense that React things in terms of components. So that's the level of granularity of React. But in real life, for many websites, thinking in terms of pages is totally sufficient. Say that you are maintaining a blog or a news website, they are typically thinking in terms of pages rather than components because they will display articles and they will, for instance, invalidate articles when they do updates to those articles. Okay. And they will have an home page with the list of articles. So they can think in terms of pages and it's a bit more intuitive to the human than components that are more for quite complex applications. All the more that it uses new features of Next that you have to set up the tag also for the fetching call that we did not need if we were using revalidatePath because we just add to use the page URL while here we need to set up a tag to later invalidate it. So it's a bit more complicated, but it's important to know both APIs. It's a bit similar to how we coded the product list. You see here that I 've been getting data from a component, so I needed to make it asynchronous and then I did add a Suspense. It's a bit convoluted because I'm doing that at component level. But you know that in Next, if you are fetching data this way at page level, you don't have to explicitly set up the Suspense because actually Next App Router does it for you and/or do. So when you go to component level, you have to do more things manually. But it's quite interesting too. It scales well and you think in terms of source of truth, which is more correct than thinking in terms of pages, even though a bit more complicated and involving.