DEV Community

Cover image for Next.js Performance Optimization with Real-World Example
Samuel Oyerinde
Samuel Oyerinde

Posted on

Next.js Performance Optimization with Real-World Example

Introduction

Building a performant web application involves balancing static and dynamic content effectively. Next.js offers a suite of features to achieve this balance, including Streaming React Server Components (RSC), Partial Prerendering (PPR), Incremental Static Regeneration (ISR), Server-Side Rendering (SSR), Static Site Generation (SSG), caching, prefetching, and suspense boundaries. Let's explore these concepts through a real-world example: a blog website with a mix of static and dynamic content.

Scenario: Blog Homepage

Our blog homepage will display:

  • Static Header and Blog Posts: These are mostly static, updated occasionally.
  • Dynamic "Latest Comments" Section: This updates frequently.

Step-by-Step Implementation

Step 1: Project Setup

  1. Directory Structure:
 /app /layout.tsx # Root layout for the app /page.tsx # Homepage route /components /BlogPostList.tsx # Component for rendering the blog post list /LatestComments.tsx # Component for rendering latest comments /lib /data.ts # Functions to fetch blog posts and comments 
Enter fullscreen mode Exit fullscreen mode
  1. Mock Data Source: Use a JSON file or API for blog posts and comments.

Step 2: Define Data Fetching Functions

In /lib/data.ts, create functions to fetch blog posts and comments:

// lib/data.ts export async function getBlogPosts() { await new Promise((resolve) => setTimeout(resolve, 1000)); // Simulate delay return [ { id: 1, title: "Blog Post 1", content: "This is the first post." }, { id: 2, title: "Blog Post 2", content: "This is the second post." }, ]; } export async function getLatestComments() { await new Promise((resolve) => setTimeout(resolve, 1500)); // Simulate delay return [ { id: 1, text: "Great post!", user: "User1" }, { id: 2, text: "Thanks for sharing!", user: "User2" }, ]; } 
Enter fullscreen mode Exit fullscreen mode

Step 3: Create Components

  1. BlogPostList Component: Use SSG with ISR for blog posts.
 // components/BlogPostList.tsx import { getBlogPosts } from "../lib/data"; export default async function BlogPostList() { const posts = await getBlogPosts(); return ( Blog Posts {posts.map((post) => ( {post.title} {post.content} ))} ); } 
Enter fullscreen mode Exit fullscreen mode
  1. LatestComments Component: Use SSR with a suspense boundary for dynamic comments.
 // components/LatestComments.tsx import { getLatestComments } from "../lib/data"; export default async function LatestComments() { const comments = await getLatestComments(); return ( Latest Comments {comments.map((comment) => ( {comment.user}: {comment.text} ))} ); } 
Enter fullscreen mode Exit fullscreen mode

Step 4: Build the Homepage

Combine static and dynamic content using Streaming SSR and Suspense.

// app/page.tsx import { Suspense } from "react"; import BlogPostList from "../components/BlogPostList"; import LatestComments from "../components/LatestComments"; export const revalidate = 600; // Enable ISR export default async function Home() { return ( My Blog {/* Static Blog Posts with SSG + ISR */} {/* Dynamic Comments with Streaming SSR and Suspense */} Loading latest comments...}> ); } 
Enter fullscreen mode Exit fullscreen mode

Step 5: Optimize Caching and Prefetching

  1. Prefetching: Use prefetch={true} in links for faster navigation.
 // components/BlogPostList.tsx (updated) import Link from "next/link"; import { getBlogPosts } from "../lib/data"; export default async function BlogPostList() { const posts = await getBlogPosts(); return ( Blog Posts {posts.map((post) => ( {post.title} {post.content} ))} ); } 
Enter fullscreen mode Exit fullscreen mode
  1. Cache Headers for Static Assets: Set cache headers in next.config.js.
 // next.config.js module.exports = { async headers() { return [ { source: "/:path*", headers: [ { key: "Cache-Control", value: "public, max-age=31536000, immutable", // Cache static assets for 1 year }, ], }, ]; }, }; 
Enter fullscreen mode Exit fullscreen mode

Explanation of Rendering Strategies

  • SSG with ISR for BlogPostList: Pre-rendered at build time, revalidated every 10 minutes.
  • Streaming SSR with PPR for LatestComments: Dynamic content is streamed as it becomes available.
  • Suspense Boundary: Ensures a smooth loading experience by showing a fallback UI.

Benefits

  1. Fast Initial Load: Static content loads immediately.
  2. Dynamic Updates: Fresh data is fetched at request time.
  3. Improved UX: Suspense boundaries prevent page blocking.
  4. Caching: Reduces server requests on repeat visits.
  5. Prefetching: Enhances navigation speed.

Tags:

#NextJS #React #WebDevelopment #PerformanceOptimization #StreamingRSC #ISR #SSG #SSR #SuspenseBoundary #Caching #Prefetching

This approach ensures a fast and user-friendly experience by leveraging Next.js's advanced features to balance static and dynamic content effectively.

Top comments (0)