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
      Cache

      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.

      Default Caching


      
      By default, GET requests using the Response object (including NextResponse) are cached in Next.js. Let’s delve into how this works with a practical example.
      
      Create app/api/time/route.ts with the following code:
      export async function GET() {
      console.log('GET /api/time');
      return Response.json({ data: new Date().toLocaleTimeString() });
      }
      Note: In development mode, the response is not cached, so the time changes with each refresh.
      
      
      In production, run npm run build && npm run start:
      
      You will observe that regardless of how many times you refresh, the time remains constant. This indicates that the response is being cached.

      Why Is This Happening?


      
      Next.js implements this by pre-rendering the content as static during the build process.
      npm run build && npm run start
      next-template@0.1.0 build next build
      ▲ Next.js 14.1.4
      Environments: .env
      Creating an optimized production build ... ✓ Compiled successfully ✓ Linting and checking validity of types✓ Collecting page dataGenerating static pages (0/10) [ ]GET /api/time ✓ Generating static pages (10/10) ✓ Collecting build traces✓ Finalizing page optimization
      Route (app) Size First Load JS ┌ ○ / 178 B 91.3 kB ├ ○ /_not-found 885 B 85.2 kB ├ λ /api/blog 0 B 0 B ├ λ /api/blog/[blogId] 0 B 0 B ├ ○ /api/time 0 B 0 B ├ ○ /blog 178 B 91.3 kB ├ λ /blog/[blogId] 145 B 84.5 kB ├ ○ /dashboard 145 B 84.5 kB └ ○ /dashboard/settings 145 B 84.5 kB
      First Load JS shared by all 84.3 kB ├ chunks/672-c944b3b6ab6fb493.js 29 kB ├ chunks/90234aad-7488aa0737955c30.js 53.4 kB └ other shared chunks (total) 1.9 kB
      ○ (Static) prerendered as static content λ (Dynamic) server-rendered on demand using Node.js
      next-template@0.1.0 start next start
      ▲ Next.js 14.1.4
      Local: http://localhost:3000
      This means the response for /api/time is determined at build time, not on the first request.

      Opting Out of Caching


      
      However, you don't need to worry about the default caching affecting your application. The conditions for default caching are strict, and there are several scenarios where caching is not applied.
      
      GET Request
      Modify app/api/time/route.ts:
      import { type NextRequest } from 'next/server';
      
      export async function GET(request: NextRequest) {
      const searchParams = request.nextUrl.searchParams
      return Response.json({ data: new Date().toLocaleTimeString(), params: searchParams.toString() })
      }
      In production, run npm run build && npm run start. The response will now be dynamically rendered, showing a different time on each request.
      npm run build && npm run start
      next-template@0.1.0 build next build
      ▲ Next.js 14.1.4
      Environments: .env
      Creating an optimized production build ... ✓ Compiled successfully ✓ Linting and checking validity of types✓ Collecting page data✓ Generating static pages (10/10) ✓ Collecting build traces✓ Finalizing page optimization
      Route (app) Size First Load JS ┌ ○ / 178 B 91.3 kB ├ ○ /_not-found 885 B 85.2 kB ├ λ /api/blog 0 B 0 B ├ λ /api/blog/[blogId] 0 B 0 B ├ λ /api/time 0 B 0 B ├ ○ /blog 178 B 91.3 kB ├ λ /blog/[blogId] 145 B 84.5 kB ├ ○ /dashboard 145 B 84.5 kB └ ○ /dashboard/settings 145 B 84.5 kB
      First Load JS shared by all 84.3 kB ├ chunks/672-c944b3b6ab6fb493.js 29 kB ├ chunks/90234aad-7488aa0737955c30.js 53.4 kB └ other shared chunks (total) 1.9 kB
      ○ (Static) prerendered as static content λ (Dynamic) server-rendered on demand using Node.js
      next-template@0.1.0 start next start
      ▲ Next.js 14.1.4
      Local: http://localhost:3000
      ✓ Ready in 223ms
      The running effect is as follows:
      
      Dynamic rendering will happen when requested, meaning that server-side request will be executed and the time will update.
      
      
      POST Request
      Modify app/api/time/route.ts:
      export async function POST() {
      console.log('POST /api/time')
      return Response.json({ data: new Date().toLocaleTimeString() })
      }
      The presence of a POST request causes dynamic rendering because POST requests typically modify data, indicating that caching may not be appropriate.
      
      • Using Dynamic Functions Like Cookies or Headers
      Modify app/api/time/route.ts:
      export async function GET(request: NextRequest) {
      const token = request.cookies.get('token')
      return Response.json({ data: new Date().toLocaleTimeString() })
      }
      Using cookies or headers results in dynamic rendering, as these values are only known at request time.
      • Manually Declaring Dynamic Mode
      Modify app/api/time/route.ts:
      export const dynamic = 'force-dynamic'
      
      export async function GET() {
      return Response.json({ data: new Date().toLocaleTimeString() })
      }
      This explicitly sets the rendering mode to dynamic.
      
      
      Revalidation
      Instead of opting out of caching, you can set cache revalidation times for less critical or less frequently updated pages.
      There are two common methods for revalidation:
      • Route Segment Configurations
      Modify app/api/time/route.ts:
      export const revalidate = 10
      
      export async function GET() {
      return Response.json({ data: new Date().toLocaleTimeString() })
      }
      Setting revalidate = 10 means the cache is revalidated at least every 10 seconds.
      However, this does not mean the server automatically updates the cache every 10 seconds. Instead, it ensures a revalidation happens at least every 10 seconds.
      For instance, if you are currently accessing /api/time and the time is on 0s, continuing to access this interface within the next 10 seconds will always return the previously cached result. After 10 seconds have passed, accessing /api/time again on the 12s will still return the cached result but trigger a server cache update. It's only when you access it on the 13s that you will receive the updated result.
      
      • next.revalidate Option
      To demonstrate this, we need an API that returns random data, such as an image API.
      Create app/api/image/route.ts:
      export async function GET() {
      const res = await fetch('https://api.thecatapi.com/v1/images/search')
      const data = await res.json()
      console.log(data)
      return Response.json(data)
      }
      In development mode, the data changes with each refresh.Next.js extends the native fetch method to automatically cache the results.
      
      Use next.revalidate to set the revalidation time for the fetch request.
      Modify app/api/image/route.ts:
      export async function GET() {
      const res = await fetch('https://api.thecatapi.com/v1/images/search', {
      next: { revalidate: 5 },
      })
      const data = await res.json()
      console.log(data)
      return Response.json(data)
      }
      Refreshing the page multiple times locally will show updated data every 5 seconds.
      
      In production, even though /api/image shows static rendering during the build, the data updates as per the revalidation rule.
      

      Summary


      
      Congratulations on completing this section! 👏👏
      In this section, we covered dynamic routes, route groups, parallel routes, and intercepting routes. Each has unique filename conventions. Dynamic routes handle dynamic links, route groups organize code, and parallel and intercepting routes address common development scenarios. While parallel and intercepting routes may seem challenging at first, following the demos in this article should help you quickly understand and master these concepts.