Taiwo Shobo
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # Understanding the advanced feature of Next.js caching mechanisms ## Introduction `Caching` is the technique of storing and retrieving data from memory. `Caching` primary function is to shorten the time it takes to retrieve data. The goal of `caching` is to save information that may come into use later. [Next.js](https://nextjs.org/) `caching` renders `data queries`, which increases application speed. Although Next.js is a fantastic framework that simplifies the process of developing `server-rendered` `React` applications, there is one major issue: The `caching` mechanism of `Next.js` may result in hard-to-debug and hard-to-fix issues in your code. `Next.js` will `cache` as much as possible to save costs and increase speed. Unless specified otherwise, `routes` are statically displayed, and `data` `requests` are `cached`. Whether a `request` is made as part of an initial visit or a follow-up navigation, whether the `route` is displayed statically or dynamically, and whether data is `cached` or uncached all affect how `caching` behaves. Depending on your use case, you may change the `caching` behavior for particular `routes` and `data` `requests`. If you’re not familiar with `Next.js` `caching` mechanism, you may find out that you’re unable to take advantage of its robust `caching` feature and, instead you always have trouble using `Next.js`. This article helps you understand how each part of Next.js `cache` operates. Once you grasp `Next.js` `cache`, you can stop struggling and start maximizing its performance improvements. ## Significance of Caching in Optimizing Web Applications `Caching` is a powerful tool that can significantly improve user experience. Here are some of its benefits: - Improves Website Performance and Load Times: - Slow website loading times can lead to user frustration and abandonment. By storing frequently accessed data, `caching` improves website performance and reduces load times, ensuring content is delivered quickly to users. - Enhances User Experience: - `Caching` results in faster load times for both websites and apps, leading to an enhanced user experience. Users can access desired content more quickly, especially during periods of heavy traffic or brief outages at the source. - Lessens the Burden on Networks and Servers: - `Caching` reduces the strain on networks and servers by serving content directly from the `cache`, thus reducing the number of `queries` made to the source. This improves `server` efficiency, lowers `data` delivery costs, and reduces network congestion. ## Nextjs caching mechanisms Understanding the [caching mechanisms in Next.js](https://nextjs.org/docs/app/building-your-application/caching) can seem daunting due to its complexity. `Next.js` employs four distinct `caching` levels, each serving a specific purpose. These mechanisms operate at different stages of your application, and their interactions may appear complex. ### Request Memoization ### Request Memoization is one of `React` inbuilt features that allows you to extend the `fetch API` to automatically `memoize` your `requests` with the same `URL` and `options`. As a result, if you make a `fetch` `request` in one component and then make the same `fetch` request in another, the second `fetch` `request` will not submit a `request` to the server. It will instead use the cached `data` from your initial `fetch` attempt. ```javascript export async function getUser() { // Next.js automatically caches the fetch function const res = await fetch(`https://jsonplaceholder.typicode.com/users/1`); return res.json(); } export default async function Page() { const user = await getUser(); return ( <> <div>{user.id}</div> <UserProfile /> </> ); } async function UserProfile() { const user = await getUser(); return <p>{user.name}</p>; } ``` In the provided example, `getUser()` function shows `request memoization`. Upon the first invocation of `getUser()` function, the returned value is cached in the Request Memoization `cache`. Subsequent calls to `getUser()` within the `UserProfile` component fetch the `data` from the cached result instead of making a new `request` to the `API`. Request Memoization optimization significantly improves code efficiency and performance by minimizing redundant `fetch` `requests`. Request memoization is necessary for reducing duplicate `fetch` `requests` within a single render cycle, particularly for `GET` `requests`. Duration: The `cache` remains active throughout the duration of a `server` `request`, persisting until the entire `React` component tree completes its rendering process. Revalidating: Request memoization is not shared across `server` `requests`; hence, revalidation is unnecessary. During the `fetch` `request`, `memoization` ensures `cache` validity, removing the need for revalidation. Opting out: To opt out of Request memoization, you can pass in an `AbortController signal` as a `parameter` to the `fetch` `request`. ```javascript export async function getUser() { const controller = new AbortController(); const res = await fetch(`https://jsonplaceholder.typicode.com/users/1`, { controller: controller.signal, }); return res.json(); } ``` By including these optimizations, `Next.js` effectively manages `caching mechanisms`, enhancing the performance and responsiveness of applications. ### Data cache `Next.js` offers a built-in `Data` `Cache` feature that retains the outcomes of `data` fetches across `server` `requests` and deployments. This ensures persistence and efficient handling of `data` retrieval from `APIs` or `databases`, enhancing performance and user experience. When initiating a `fetch` request within `server` components, `Next.js` automatically `caches` the `response` by default. This cached `data` is then used for subsequent `requests`, removing redundant `fetches`. Let’s have a simple page that send a `fetch` `request` to get a particular post. ```javascript async function Page() { const res = await fetch(`https://jsonplaceholder.typicode.com/posts/1`); const data = await res.json(); return ( <div> <h2>{data.title}</h2> </div> ); } export default Page; ``` When you initiate a `fetch` `request` during rendering, `Next.js` examines the Data Cache to find a potential cached response. If a cached response exists, it is promptly returned to you and `memoized`. If there's no cached `response`, the system sends your `request` to the data source, stores the outcome in the Data Cache, and then `memoizes` it. For uncached data ``(e.g. { cache: 'no-store' })``, the result is always fetched from the data source, and memoized. Regardless of whether your data is cached or uncached, all your `requests` undergo `memoization`, ensuring you avoid redundant `requests` for the same data during a `React` render pass. Duration: Data cached from the `fetch` `request` is never cleared until you instruct Nextjs to clear it, Data `cache` remains persistent throughout incoming `request` and deployment unless you choose to `revalidate` it or `opt out`. Revalidating: Since data `cache` cannot be cleared, there must be a way to `revalidate` it. It can be revalidated in two possible ways: * Time-based Revalidation: In `time-based revalidation`, we set a certain time limit. When a new `request` is made after this time has passed, the `data` `cache` will clear automatically. This helps keep the `cache` updated by removing outdated information. You can pass the `next.revalidate` option in the `fetch` `request` to set the `cache time-bound`(Note: Always in seconds). Look into the code below: ```javascript const res = fetch(`https://jsonplaceholder.typicode.com/users/1`, { next: { revalidate: 3600 }, }); ``` With this, Next.js will get to know how many seconds to keep your `data` in the `cache` before it is considered stale. The first time the `fetch` request is called with the `next.revalidate`, the data will be fetched from the source and it will will cached and stored in Data cache. Any `fetch` request call within this timeframe passed in the initial `request`, the data returned will be from the Data cache that has been stored and cached. Any `request` after the time-bound will return the cached data (Now, the data value has become stale). After the time-bound, Next.js will `revalidate` the data in the background. When the data is successfully obtained, Next.js will update the Data Cache with the new information. However, if the background `revalidation` fails, the previous data will stay unaffected. - On-demand Revalidation: If your data isn't regularly updated, `on-demand revalidation` becomes valuable. Consider a scenario where you've built a blog using a Content Management System (CMS). In this case, leveraging `on-demand revalidation` allows you to `invalidate` the `cache` and `fetch` new `data` whenever a recent article is published, ensuring your content remains up-to-date. Data can be `revalidate` in two different ways: - revalidatePath function: revalidatePath function allows you to `invalidate` cached content for a specified path lazily, meaning it only occurs when you revisit that `path`. This targeted invalidation prevents unnecessary revalidations across your site, making it possible for efficient cache management. ```javascript import { revalidatePath } from "next/cache"; export async function pubBlog({ state }) { createArticle(state); revalidatePath(`/location/${state}`); } ``` The `revalidatePath` function accepts a string path and clears the cache for all `fetch` requests on that route. - revalidateTag function: revalidateTag function gives you control to `invalidate` cached content associated with a specific `tag` in `Next.js`. When you call it, it purges cached pages and data matching that tag, triggering fresh generation when you next visit those pages. If you want to be really clear about which `fetch` requests to check again, you can use the `revalidateTag` function. ```javascript const res = fetch(`https://.../${state}`, { next: { tags: ["location-state"] }, }); ``` Opting out: To `opt out` of `data` `cache` can be carried out in different way. Let’s take a look at the example for each of them. - No-store: ```javascript const res = fetch(`https://… `, { cache: "no-store", }) ``` Passing cache: ``"no-store"`` to your `fetch` request, you are telling Next.js not to `cache` this request in the Data Cache. And this is sometime useful when you intend to change the data on each request. - Unstable_noStore: ```javascript import { unstable_noStore as noStore } from "next/cache" function getProducts() { noStore() const res = fetch(`https://.../${products}`) } ``` Opting out of caching on a per-component or per-function basis is a fantastic way for you to have more control. Unlike other methods, which opt out of the Data Cache for the entire page, this approach allows you greater flexibility. - Dynamic function: ```javascript export const dynamic = 'force-dynamic' ``` Suppose you intend to change the behavior on how the entire page is cached, now limiting it to a specific `fetch` `request`. In that case, you can include this code snippet at the top level of the file, which will remove the Data cache entirely and make the page dynamic. By supplying `cache`: `"no-store"` to your `fetch` `request`, you instruct Next.js not to `cache` this `request` in the Data Cache. This is handy when you frequently change data and want to get it fresh every time. - Revalidate: ```javascript export const revalidate = 0 ``` This is also similar to the `force dynamic` mentioned above; once you equate the `revalidate to 0`, it will tell `Nextjs` to ensure that all the fetch `requests` on the particular page are not cached or stored. ### Full route cache When you render pages for your clients in `Next.js`, you employ both `HTML` and the `React Server Component Payload (RSCP)` to guide `client components` on how to interact with `server components` for page rendering. The Full Route Cache comes into play here, storing both `HTML` and `RSCP` for static pages throughout the build process. As you build your application, `Next.js` automatically renders and `caches` `routes`. This optimization allows cached `routes` to be served instead of rendering on the `server` for each request, resulting in faster page loads. The main advantage of this `cache` is that it enables you to `cache` static pages at build time, removing the need to generate such pages dynamically. Consider the following example: ```javascript import Link from "next/link"; async function getBlog() { const blogPosts = await fetch("https://jsonplaceholder.typicode.com/posts"); return await blogPosts.json(); } export default async function Page() { const blogInfo = await getBlog(); return ( <div> <h1>Blog Posts</h1> <ul> {blogInfo?.map((post) => ( <li key={post.id}> <h3>{post.title}</h3> <p>{`${post.body.slice(0, 20)}...`}</p> <p> <Link href={`/blog/${post.id}`}>Read more</Link> </p> </li> ))} </ul> </div> ); } ``` In the provided code snippet, the Page lacks `dynamic data`, allowing for `caching` during the `build time`. The complete `route` `cache` stores both `HTML` and `RSCP`, significantly enhancing server speed when a user requests access to that particular `route`. Duration: By default, your Full Route Cache is persistent, meaning that the render output is cached across your user requests. Revalidating: The only way this `HTML/RSCP` will be updated is through: * Revalidating data: Revalidating the Data Cache will, in turn, `invalidate` the Router Cache by re-rendering `server` components and `caching` the new render output. * Redeployment: Unlike the Data Cache, which persists across deployments, new deployments clear the Full Route Cache. Opting out: To opt out of the Full Route Cache,you will have to opt out of the Data Cache. If the data needed for the page is not cached in the Data Cache, you can consider the second approach: incorporate dynamic elements like `headers`, `cookies`, `searchParams`, or `dynamic URL` `parameters` in your page. ### Router cache In Next.js, you'll encounter the Router Cache, which functions differently compared to traditional `server-side` `caching`. Instead of `caching` on the `server`, it stores `cache` data on the `client-side`. Understanding its functionality is crucial for you to avoid potential issues and optimize performance. Basically, it stores the `routes` you've visited locally on your device, enabling quicker access to cached versions rather than fetching fresh content from the `server`. Mastering its operation allows you to manage any challenges effectively. How the Router Cache Works: ```javascript import Link from "next/link"; export default async function Page() { const blogInfo = await getBlog(); return ( <div> <h1>Blog Posts</h1> <ul> {blogInfo?.map((post) => ( <li key={post.id}> <h3>{post.title}</h3> <p>{`${post.body.slice(0, 20)}...`}</p> <p> <Link href={`/blog/${post.id}`}>Read more</Link> </p> </li> ))} </ul> </div> ); } ``` Next.js `caches` the `route` segments you visit and preloads likely `routes` based on `<Link>` components in your viewport. This makes your navigation experience smoother. Navigate backward and forward instantly since the app `caches` visited `routes`. Explore new `routes` quickly, thanks to prefetching and partial rendering. No need for full-page refreshes between navigations, keeping your `React` and browser `states` intact. Duration: The behavior of the `Router Cache` varies depending on the `route` type and `duration` of storage. For static `routes`, the `cache` persists for 5 minutes, while for `dynamic` `routes`, it lasts only 30 seconds. If you revisit a `static route` within 5 minutes, the cached version is used. After 5 minutes, a `server request` fetches the new `HTML/RSCP`. Dynamic `routes` follow a similar process but with a 30-second cache instead of 5 minutes. This cache is session-based and clears when you close the tab or refresh the page. Revalidating: You have the option to manually `revalidate` the Router Cache by clearing the `data cache` from a `server` action using `revalidatePath/revalidateTag`. Additionally, invoking the `router.refresh function`, obtained from the `useRouter` hook on your `client-side` code, forces the client to refetch the current page. Opting out: There's no direct way for you to opt out of the Router Cache. However, given the various methods available for cache revalidation, it's not a significant concern for you to worry about. ## Pros and cons of Nextjs cache mechanism ### Pros - In Next.js, the `caching` mechanism works to remove redundant data `fetching for you`. When data is fetched and cached, This approach helps reduce the `server` load, providing you with more efficient `data handling`. - Effective caching strategies involve understanding the trade-offs between immediate consistency and the performance benefits of serving stale content. - Next.js `cache` mechanism introduces advanced `revalidation patterns`, allowing developers to fine-tune how their application manages `data fetching`, `caching`, and `validation`. Using `time-based` and `event-driven` `revalidation`, these helps developers build strong systems that maintain data up to date without losing user experience. ### Cons - In Next.js 14, you can perform `server-side` data fetching using third-party libraries. These libraries often come with their own `methods` for `caching` and `revalidation`, offering you more control or additional capabilities compared to the built-in retrieval. - Caching can speed up data `fetching` and `rendering`, but it also increases memory usage. Caching large amounts of data may strain `server` resources, impacting overall performance. - Be mindful of `cache` invalidation challenges. When server data changes, Next.js caching mechanism might struggle to update the cache, leading to users receiving outdated information. ## How do cache interact with each other Understanding how caching techniques interact with each other is crucial for effective implementation. ### Data Cache and Full Route Cache - When `revalidating` or `opting-out` of the Data Cache, the Full Route Cache is invalidated since the render result depends on the `data`. - The Data Cache remains unaffected by `invalidating` or `opting-out` of the Full Route Cache. This allows for dynamically displaying a `route` with both cached and uncached data. ### Data cache and client-side router cache - Revalidating the Data Cache in a Route Handler doesn't immediately `invalidate` the Router Cache, as it's not tied to a specific `route`. - To promptly `invalidate` both the Data Cache and Router Cache, you have to use `revalidatePath` or `revalidateTag` in a `Server Action`. ## Conclusion In conclusion, understanding Next.js caching mechanisms is crucial for optimizing your web application's `performance`. `Caching`, at various levels such as `Request Memoization`, `Data Cache`, `Full Route Cache`, and `Router Cache`, plays a pivotal role in reducing load times, enhancing user experience, and efficiently managing `server` resources. Each caching level operates distinctly, and knowing how to leverage features like `time-based` and `on-demand revalidation` allows you to fine-tune your application for optimal results.

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully