Teachnique
      CourseRoadmaps
      Login

      Introduction

      Project SetupCLI

      IntroductionAPP RouterTemplateLoading UIError Handling404 Page

      Linking and Navigating

      Dynamic RoutesRoute groupsParallel RoutesIntercepting Routes

      Route handlersCacheCommon Questions

      Middleware

      CSRSSR & SSGISR

      React Server ComponentsServer-Side Rendering

      SuspenseStreaming

      Server & Client ComponentServer vs. Client ComponentBest Practices

      Server-Side Rendering Strategies

      Data Fetching & Caching & RedirectThird-Party Request Libraries on the Server SideBest Practices

      Request MemoizationData CacheFull Route CacheRouter Cache

      Server Actions IFormServer Actions IIOptimistic Update

      Tailwind CSSCSS-in-JSSass

      Environment VariablesAbsolute Imports& Module Path AliasesRoute Segment Config

      Image & LCPImage IImage IIOptimizing IOptimizing II

      Next FontFont ParameterApply Styles

      Feedback

      Submit request if you have any questions.

      Course
      Server-Side Rendering Strategies

      Next.js Mastery: From Fundamentals to Full-Stack

      Unlock the power of Next.js with this comprehensive course! Starting with the basics, you’ll learn essential skills such as routing, data fetching, and styling. Progress through practical projects, including building your own React Notes app, to gain hands-on experience. Dive into the source code to understand the inner workings and core principles of Next.js. Perfect for developers with a basic knowledge of React and Node.js, this course ensures you’ll be ready to create high-performance full-stack applications efficiently. Join us and master Next.js, backed by industry experts and a supportive learning community.

      Introduction

      Now let's create a new file, app/server/page.js, with the following code:
      export default async function Page() {
      const url = (await (await fetch('https://api.thecatapi.com/v1/images/search')).json())[0].url
      return (
      <img src={url} width="300" alt="cat" />
      )
      }
      The URL https://api.thecatapi.com/v1/images/search returns a random cat image each time it is called.
      Let's run npm run dev. In development mode, refreshing the page returns a new image each time:
      
      However, after running npm run build && npm run start, refreshing the page always returns the same cat image:
      
      Why is this happening?
      Let's look at the build output:
      
      
      /server is marked as Static, meaning it is pre-rendered as static content. This means the returned content for /server is determined at build time. The image displayed on the page is the one fetched during the build.
      So, how can we make /server return a new image each time?
      This leads us to Next.js's server-side rendering strategies.

      Server-Side Rendering Strategies


      
      Next.js has three different server-side rendering strategies:
      1. Static Rendering
      2. Dynamic Rendering
      3. Streaming
      Let's introduce each of these.

      Static Rendering

      Static Rendering is the default rendering strategy. Routes are rendered at build time or re-rendered in the background after revalidation, and the results can be cached and pushed to a CDN. This is suitable for non-personalized data that is known in advance, such as static blog posts or product pages.
      In the example above, the page was rendered at build time. To re-render after revalidation, you can use a route segment configuration option like revalidate.
      Modify app/server/page.js to include:
      export const revalidate = 10
      
      export default async function Page() {
      const url = (await (await fetch('https://api.thecatapi.com/v1/images/search')).json())[0].url
      return (
      <img src={url} width="300" alt="cat" />
      )
      }
      Even though /server is still marked as Static in the build output, the image now updates periodically:
      
      The revalidate = 10 line sets a revalidation frequency of 10 seconds. Note:
      • The code does not make the server automatically update /server every 10 seconds.
      • Instead, it triggers revalidation at least 10 seconds after the last request.
      For example, if you access /server at time 0s and continue to access it within the next 10 seconds, the returned image remains the same. After 10 seconds, a new request at 12s still returns the cached result, but triggers a cache update. The next request at 13s returns the updated result.

      Dynamic Rendering

      Dynamic Rendering occurs at request time, suitable for personalized data or data dependent on request information (e.g., cookies, URL parameters).
      When using dynamic functions or uncached data requests, Next.js switches to Dynamic Rendering:
      Dynamic Function
      Data Cache
      Rendering Strategy
      No
      Cached
      Static Rendering
      Yes
      Cached
      Dynamic Rendering
      No
      Uncached
      Dynamic Rendering
      Yes
      Uncached
      Dynamic Rendering
      As a developer, you don't need to choose between static or dynamic rendering. Next.js automatically selects the best strategy based on the features and APIs you use for each route.

      1. Dynamic Functions

      Dynamic functions fetch information only available at request time (e.g., cookies, request headers, URL parameters). In Next.js, these include:
      • cookies() and headers() for cookies and headers
      • searchParams for query parameters
      Using any of these functions triggers dynamic rendering.
      Example 1: Using Cookies
      Modify app/server/page.js:
      import { cookies } from 'next/headers'
      
      export default async function Page() {
      const cookieStore = cookies()
      const theme = cookieStore.get('theme')
      
      const url = (await (await fetch('https://api.thecatapi.com/v1/images/search')).json())[0].url
      return (
      <img src={url} width="300" alt="cat" />
      )
      }
      Running npm run build && npm run start, /server is dynamically rendered:
      
      
      Example 2: Using searchParams
      Modify app/server/page.js:
      export default async function Page({ searchParams }) {
      const url = (await (await fetch('https://api.thecatapi.com/v1/images/search')).json())[0].url
      return (
      <>
      <img src={url} width="300" alt="cat" />
      {new Date().toLocaleTimeString()}
      {JSON.stringify(searchParams)}
      </>
      )
      }
      Running npm run build && npm run start, /server is dynamically rendered:
      
      
      However, the image does not change on page refresh.
      
      This is because data request caching is separate from rendering strategy. Even with dynamic rendering, the fetch request is cached, resulting in the same image.
      Modify app/server/page.js to disable caching:
      export default async function Page({ searchParams }) {
      const url = (await (await fetch('https://api.thecatapi.com/v1/images/search', { cache: 'no-store' })).json())[0].url
      return (
      <>
      <img src={url} width="300" alt="cat" />
      {new Date().toLocaleTimeString()}
      {JSON.stringify(searchParams)}
      </>
      )
      }
      With cache: 'no-store', the fetch request does not cache, and the image updates on refresh:
      
      

      2 Using Uncached Data Requests

      By default, fetch results are cached. However, you can configure fetch requests to skip caching. This makes the route dynamically rendered:
      • Add { cache: 'no-store' } to fetch requests.
      • Add revalidate: 0 to fetch requests.
      • Use POST method in route handlers.
      • Fetch after using headers or cookies.
      • Configure const dynamic = 'force-dynamic'.
      • Set fetchCache route segment option to skip caching.
      • Use Authorization or Cookie headers in fetch requests, combined with an uncached request higher in the component tree.
      For example:
      export default async function Page() {
      const url = (await (await fetch('https://api.thecatapi.com/v1/images/search', { cache: 'no-store' })).json())[0].url
      return (
      <>
      <img src={url} width="300" alt="cat" />
      {new Date().toLocaleTimeString()}
      </>
      )
      }
      This renders the page dynamically and fetches a new image each time the page is refreshed.

      Streaming

      Using loading.js or the React Suspense component enables Streaming. Refer to the "Rendering | Suspense and Streaming" section for more details.

      Other Terms for Clarification


      
      In addition to static rendering, dynamic rendering, dynamic functions, and uncached data requests, you may encounter related terms like partial rendering and dynamic routes in the documentation. Here’s a breakdown to help distinguish them.

      1. Partial Rendering

      Partial rendering refers to re-rendering only the changed route segments during client-side navigation while retaining shared segments. For example, navigating between /dashboard/settings and /dashboard/analytics, re-renders settings and analytics pages but retains the shared dashboard layout:
      
      
      Partial rendering aims to reduce data transfer and execution time during route changes, improving performance.

      2. Dynamic Routes

      Dynamic routes were covered in "Routing | Dynamic Routes, Route Groups, Parallel Routes, and Intercepting Routes":
      export default function Page({ params }) {
      return <div>My Post: {params.slug}</div>
      }
      Dynamic routes are not necessarily dynamically rendered; you can statically generate routes using generateStaticParams.
      Sometimes, dynamic routes (Dynamic Routes) are used to refer to "dynamically rendered routes." The documentation rarely uses the term static routes (Static Routes), but when it does, it refers to "statically rendered routes."

      3. Dynamic Segment

      Dynamic segments are parts of the route that are dynamic. For example, in app/blog/[slug]/page.js, [slug] is a dynamic segment.

      Summary

      Congratulations on completing this section!
      We've covered the three server-side rendering strategies in Next.js. This wraps up our discussion on rendering, and we’ll now move on to data fetching.