Skip to content
FullStackDostFullStackDostLearn · Build · Level Up
  • All Courses
  • Updates
  • My Account
  • Practice
  • Data Strcture
  • FSD
  • All Courses
  • Updates
  • My Account
  • Practice
  • Data Strcture
  • FSD
  • Home
  • Web development

Next.Js (React.JS framework) 12 Sections142 Lessons1 Quiz10 Weeks

Curriculum

  • 12 Sections
  • 142 Lessons
  • 10 Weeks
Expand all sectionsCollapse all sections
  • Introduction to Next.js
    9 Items
    Introduction to Next JS and comparison with other frameworks.
    • 1.1
      What is Next.js?
      10 Minutes
    • 1.2
      Why use Next.js?
    • 1.3
      Next.js vs React
      10 Minutes
    • 1.4
      Next.js vs other frameworks
    • 1.5
      Key features and achitecture
    • 1.6
      How Rendering Works in Next.js
    • 1.7
      App Router vs. Pages Router: Navigating Next.js Routing Systems
    • 1.8
      Prerequisites: HTML, CSS, JavaScript and React
    • 1.9
      Introduction to Next JS
      10 Minutes5 Questions
  • Installation and setup
    9 Items
    Installation and setup Next.js
    • 2.1
      Node.js and environment setup
    • 2.2
      Create a Next.js application
      15 Minutes
    • 2.3
      Run the development server
    • 2.4
      Project folder structure
    • 2.5
      Understanding package.json and scripts
    • 2.6
      TypeScript setup
    • 2.7
      ESLint and code quality
    • 2.8
      Path aliases and the src directory
    • 2.9
      Development vs production builds
  • Routing, pages and layout
    15 Items
    Routing, pages and layout
    • 3.1
      File-system-based routing
    • 3.2
      Creating pages with page.tsx
    • 3.3
      Shared layouts with layout.tsx
    • 3.4
      Nested layouts
    • 3.5
      Link component and navigation
    • 3.6
      Dynamic route segments
    • 3.7
      Catch-all and optional catch-all routes
    • 3.8
      Route groups
    • 3.9
      Private folders
    • 3.10
      Loading UI with loading.tsx
    • 3.11
      Error handling with error.tsx
    • 3.12
      not-found.tsx
    • 3.13
      Parallel routes
    • 3.14
      Intercepting routes
    • 3.15
      Programmatic navigation and redirects
  • React component and fundamentals
    11 Items
    React component and fundamentals
    • 4.1
      React components in Next.js
    • 4.2
      Server Components
    • 4.3
      Client Components
    • 4.4
      The use client directive
    • 4.5
      Choosing server or client rendering
    • 4.6
      Composing server and client components
    • 4.7
      Props and component reuse
    • 4.8
      State and event handlers
    • 4.9
      Forms and controlled inputs
    • 4.10
      Context and providers
    • 4.11
      Third-party client libraries
  • Styling, assets and user interface (UI)
    10 Items
    • 5.1
      Global CSS
    • 5.2
      CSS Modules
    • 5.3
      Tailwind CSS
    • 5.4
      Sass and CSS-in-JS
    • 5.5
      Fonts with next/font
    • 5.6
      mages with next/image
    • 5.7
      Static assets and the public folder
    • 5.8
      Responsive design
    • 5.9
      Layouts and reusable UI patterns
    • 5.10
      Scripts with next/script
  • Data fetching and rendering
    13 Items
    • 6.1
      Fetching data in Server Components
    • 6.2
      Using the fetch API
    • 6.3
      Database and ORM integration
    • 6.4
      Fetching in Client Components
    • 6.5
      Sequential vs parallel fetching
    • 6.6
      Data loading states
    • 6.7
      Streaming and Suspense
    • 6.8
      Static rendering
    • 6.9
      Dynamic rendering
    • 6.10
      Server-side rendering concepts
    • 6.11
      Client-side rendering
    • 6.12
      Partial prerendering concepts
    • 6.13
      Environment variables and server-only code
  • Caching and data updates
    11 Items
    • 7.1
      Understanding cache fundamentals
    • 7.2
      Data Cache and rendered output
    • 7.3
      Cache Components and the use cache directive
    • 7.4
      Cache boundaries and lifetimes
    • 7.5
      Revalidation strategies
    • 7.6
      Time-based revalidation
    • 7.7
      On-demand revalidation
    • 7.8
      revalidatePath
    • 7.9
      revalidateTag
    • 7.10
      Request deduplication
    • 7.11
      Optimistic UI and fresh data
  • Backend development and mutations
    12 Items
    • 8.1
      Route Handlers
    • 8.2
      GET, POST, PUT, PATCH and DELETE
    • 8.3
      NextRequest and NextResponse
    • 8.4
      Server Functions and Server Actions
    • 8.5
      Form submissions
    • 8.6
      Validation and error handling
    • 8.7
      Database CRUD operations
    • 8.8
      Cookies and headers
    • 8.9
      File uploads
    • 8.10
      Webhooks
    • 8.11
      Backend-for-Frontend patterns
    • 8.12
      API security
  • Authentication and Security
    12 Items
    • 9.1
      Authentication vs authorization
    • 9.2
      Sessions and cookies
    • 9.3
      Login and logout flows
    • 9.4
      Protecting routes and layouts
    • 9.5
      Authorization checks near data access
    • 9.6
      Role-based access control
    • 9.7
      Using authentication libraries
    • 9.8
      Environment secrets
    • 9.9
      Input validation
    • 9.10
      CSRF and request security
    • 9.11
      Content Security Policy
    • 9.12
      Data security and safe serialization
  • SEO, performance and accessibility
    14 Items
    • 10.1
      Metadata API
    • 10.2
      Dynamic metadata
    • 10.3
      Open Graph images
    • 10.4
      Sitemaps and robots.txt
    • 10.5
      Canonical URLs
    • 10.6
      Font and image optimization
    • 10.7
      Link prefetching
    • 10.8
      Lazy loading
    • 10.9
      Bundle analysis
    • 10.10
      Core Web Vitals
    • 10.11
      Accessibility fundamentals
    • 10.12
      Analytics and Speed Insights
    • 10.13
      Internationalization
    • 10.14
      Redirects and rewrites
  • Testing, deployment and production
    13 Items
    • 11.1
      Unit and component testing
    • 11.2
      Jest and Vitest
    • 11.3
      End-to-end testing with Playwright or Cypress
    • 11.4
      Build and production start
    • 11.5
      Deployment to a managed platform
    • 11.6
      Self-hosting with Node.js or Docker
    • 11.7
      Static export
    • 11.8
      CI/CD pipelines
    • 11.9
      Logging and monitoring
    • 11.10
      Instrumentation and OpenTelemetry
    • 11.11
      Production security checklist
    • 11.12
      Troubleshooting and debugging
    • 11.13
      Upgrading Next.js and codemods
  • Advanced topics and Pages Router
    14 Items
    • 12.1
      Middleware concepts and Proxy conventions
    • 12.2
      Edge Runtime
    • 12.3
      Custom servers
    • 12.4
      Multi-Zones
    • 12.5
      Progressive migration from Pages Router
    • 12.6
      Pages Router pages and layouts
    • 12.7
      getStaticProps
    • 12.8
      getServerSideProps
    • 12.9
      getStaticPaths
    • 12.10
      API Routes
    • 12.11
      Pages Router data fetching
    • 12.12
      useRouter and router events
    • 12.13
      Legacy image and head APIs
    • 12.14
      Migrating Pages Router applications

How Rendering Works in Next.js

Introduction to Next.js Rendering

Namaste, Future Full-Stack Dosts! Welcome to a crucial lesson that will truly elevate your Next.js development skills. Understanding how Next.js renders your applications is like knowing the engine of a high-performance car – it’s fundamental to building fast, efficient, and user-friendly web experiences. In this lesson, we’ll demystify the core concepts of rendering, from where your code executes to how it ultimately displays on a user’s screen. We’ll explore various rendering strategies and how Next.js intelligently combines them to deliver optimal performance.

Rendering is essentially the process of transforming your React components into a user interface that a browser can display. Next.js, being a powerful React framework, offers flexible rendering environments: on the server, in the browser, or a clever combination of both. Let’s dive in!

EduPress Graphic Suggestion: A modern, clean infographic showing a journey from ‘Code’ to ‘User Screen’ with branching paths for ‘Server’ and ‘Browser’ execution. Icons for each rendering type (e.g., a server rack for SSR, a browser window for CSR, a frozen block for Static) could highlight the paths.

Key Concepts of Rendering in Next.js

1. Client-Side Rendering (CSR)

Client-Side Rendering (CSR) is perhaps the most familiar rendering approach for traditional React developers. In CSR, the browser downloads a minimal HTML page along with JavaScript bundles. The browser then executes this JavaScript to build the entire UI directly within the user’s browser.

EduPress Graphic Suggestion: A flow diagram: ‘Browser Request’ → ‘Server sends HTML/JS’ → ‘Browser downloads JS’ → ‘Browser executes JS (React renders UI)’ → ‘User interacts’. Highlight the ‘Browser’ as the primary worker.

How it works:

  1. The browser requests a page.
  2. The server sends a basic HTML document (often just a root <div id="root"></div>) and references to JavaScript resources.
  3. The browser downloads and executes the JavaScript.
  4. React renders or updates the UI based on this JavaScript.
  5. The user can then interact with the fully loaded page.

When to use it:

  • For highly interactive dashboards and single-page applications where initial load time for static content is less critical than dynamic interactions.
  • When SEO is not a primary concern (as search engine crawlers might struggle with empty initial HTML).
  • For parts of a page that require frequent, real-time updates and direct browser API access.

2. Server-Side Rendering (SSR)

Server-Side Rendering (SSR) brings the rendering process to the server. For each request, the server executes the React components, generates the full HTML for the page, and sends this HTML to the browser. This means the user sees content much faster, as the browser doesn’t have to wait for JavaScript to download and execute before displaying anything.

EduPress Graphic Suggestion: A flow diagram: ‘Browser Request’ → ‘Server executes rendering logic (React)’ → ‘Server sends HTML’ → ‘Browser displays HTML’ → ‘JS loads & Hydrates’. Emphasize the ‘Server’ doing the heavy lifting initially.

How it works:

  1. The browser requests a page.
  2. The server executes the necessary rendering logic for the page, fetching data if required.
  3. The server generates and sends a complete HTML document to the browser.
  4. The browser displays this HTML immediately.
  5. JavaScript then loads in the background and "hydrates" the page, making interactive Client Components functional.

When to use it:

  • For pages requiring up-to-date data on every request, like a user’s personalized dashboard or a dynamic product listing.
  • When SEO is crucial, as search engine crawlers receive fully formed HTML content.
  • To improve the First Contentful Paint (FCP) and overall perceived performance.

3. Static Rendering (SSG)

Static Rendering, often referred to as Static Site Generation (SSG), means generating the page’s HTML output ahead of an individual request, typically at build time. Once built, these static HTML files can be served very quickly from a Content Delivery Network (CDN), offering unparalleled performance and scalability.

Consider an "About Us" page – its content doesn’t change frequently. Next.js can pre-render this page into a static HTML file once, and then serve that same file to millions of users without needing to recompute it for every request.

Code Example: Static Page

// app/about/page.tsx
export default function AboutPage() {
  return (
    <main>
      <h1>About Our Company</h1>
      <p>We are dedicated to building innovative software solutions.</p>
      <p>Our mission is to empower businesses with cutting-edge technology.</p>
    </main>
  );
}

In the App Router, by default, all components are Server Components, and Next.js automatically statically renders routes when possible. If a route doesn’t use dynamic functions or uncached data fetches, it will be statically rendered.

When to use it:

  • For content that doesn’t change frequently, such as marketing pages, documentation, blogs, and e-commerce product pages.
  • When maximum performance, security, and scalability are critical.
  • For highly cacheable content that can be served directly from a CDN.

4. Dynamic Rendering

Dynamic rendering is essentially a specific form of Server-Side Rendering (SSR) where the output of a page depends on request-specific information. This means the page cannot be pre-rendered at build time or cached for all users, as its content changes based on the incoming request (e.g., user session, headers, URL parameters).

Next.js automatically switches a route to dynamic rendering if it detects the use of dynamic functions (like cookies(), headers(), searchParams) or if it encounters an uncached fetch() request during rendering.

Code Example: Dynamic Page (reading cookies)

// app/account/page.tsx
import { cookies } from "next/headers"; // Next.js dynamic function
export default async function AccountPage() {
  // Accessing cookies makes this page dynamically rendered
  const cookieStore = cookies();
  const session = cookieStore.get("session");
  // For a real application, you'd validate this session for authentication
  const isAuthenticated = session?.value === "your-secret-session-id"; // Simplified check
  return (
    <main>
      <h1>Your Account</h1>
      {isAuthenticated ? (
        <p>Welcome back! Your session is active.</p>
      ) : (
        <p>Please log in to access your account details.</p>
      )}
    </main>
  );
}

In this example, because we are reading cookies (a request-specific API), Next.js determines that this page must be rendered dynamically on the server for each incoming request. This ensures the user sees content relevant to their specific session.

When to use it:

  • For pages that require personalized content based on user authentication, session data, or other request-time information.
  • When the content changes too frequently or is too unique per user to be statically generated.

5. Hydration

Hydration is a critical concept that bridges the gap between server-rendered HTML and interactive client-side React applications. When a server (via SSR or SSG) sends pre-rendered HTML to the browser, this HTML is static and non-interactive.

Hydration is the process where React takes over this server-rendered HTML, attaches client-side JavaScript event listeners, and makes the components interactive. It effectively "wakes up" the static HTML with dynamic behavior.

EduPress Graphic Suggestion: A visual showing static HTML elements (e.g., a greyed-out button) transforming into interactive, colorful elements as JavaScript flows into them. Text labels: ‘Server Rendered HTML (Static)’ → ‘JavaScript Loads’ → ‘Hydration’ → ‘Interactive UI’.

A simplified view:

  1. Server Rendering: Generates HTML on the server.
  2. Browser Displays HTML: User sees content quickly (First Contentful Paint).
  3. JavaScript Loads: Client-side React code downloads.
  4. Hydration: React executes, matches the virtual DOM to the server-rendered HTML, and attaches event handlers.
  5. Interactive UI: Components become fully interactive.

Hydration Errors: These occur when the initial browser render (after JavaScript executes) does not precisely match the HTML produced by the server. Common causes include:

  • Rendering different content based on client-side vs. server-side conditions (e.g., window object access on the server).
  • Producing invalid HTML (e.g., incorrect nesting of tags).
  • Differences in timestamps or locale-specific formatting between server and client.

Next.js will warn you about hydration errors in development mode, and it’s essential to fix them to ensure a seamless user experience.

6. Streaming and Suspense

Imagine a page with multiple sections, some of which take longer to load data than others. Traditionally, the entire page would have to wait for the slowest section to finish before any content could be displayed. This leads to a blank screen or a full-page spinner, frustrating users.

Streaming in Next.js allows you to send parts of a server-rendered page to the browser as soon as they are ready, rather than waiting for the entire page to complete. This significantly improves perceived loading performance.

React Suspense works hand-in-hand with streaming. It allows you to define a loading fallback (e.g., a spinner or a skeleton UI) for parts of your UI that are still fetching data or rendering. When the data for that section is ready, the fallback is replaced with the actual content.

Code Example: Streaming with Suspense

// app/dashboard/page.tsx
import { Suspense } from "react";
// A component that fetches data and might take some time
async function Reports() {
  // Simulate a network delay
  await new Promise(resolve => setTimeout(resolve, 2000)); 
  const response = await fetch("https://api.example.com/reports");
  if (!response.ok) {
    throw new Error("Could not load reports");
  }
  const reports = await response.json();
  return (
    <div style={{ border: '1px solid #ccc', padding: '15px', borderRadius: '5px' }}>
      <h3>Latest Reports</h3>
      <pre>{JSON.stringify(reports, null, 2)}</pre>
    </div>
  );
}
export default function DashboardPage() {
  return (
    <main>
      <h1>Welcome to Your Dashboard</h1>
      <p>Here's an overview of your activity:</p>
      {/* This section will stream in independently */}
      <Suspense fallback={<p style={{ color: '#007bff' }}>Loading important reports...</p>}>
        <Reports />
      </Suspense>
      <div style={{ marginTop: '30px', borderTop: '1px dashed #eee', paddingTop: '20px' }}>
        <h3>Other Dashboard Content</h3>
        <p>This content loads immediately.</p>
      </div>
    </main>
  );
}

In this example, the Reports component is a Server Component that simulates a data fetch. By wrapping it in <Suspense>, the rest of the DashboardPage can be rendered and streamed to the client immediately, while the "Loading important reports…" fallback is shown until the Reports data is ready. Once ready, the actual reports content is streamed and replaces the fallback.

Next.js also supports route-level loading interfaces using a loading.tsx file, which you’ll explore in detail in a later module. This provides a loading state for an entire route segment.

Rendering Comparison and Important Distinction

It’s vital to understand that these rendering approaches are not mutually exclusive. A single Next.js page can intelligently combine static output, server-rendered data, streamed sections, and interactive Client Components for different parts of its UI.

EduPress Graphic Suggestion: A comparison table (similar to the one below but visually enhanced) with icons for each rendering type. Use color coding to quickly convey benefits (e.g., green for high performance, yellow for dynamic). Example icons: ‘clock’ for build time, ‘refresh’ for request time, ‘browser’ for client, ‘server’ for server.

Quick Comparison:

Rendering ApproachWhen Work HappensTypical Use CasesKey Benefit
Static Rendering (SSG)Ahead of an individual request (build time)Marketing pages, documentation, blogs, e-commerce product listingsMaximum performance, scalability, CDN caching
Dynamic Server Rendering (SSR)During a request (on the server)Request-specific pages, authenticated dashboards, dynamic data feedsAlways fresh data, good SEO, fast initial load (FCP)
Client-Side Rendering (CSR)In the browser (after initial HTML load)Highly interactive widgets, browser-dependent UI, dynamic formsRich interactivity, reduced server load for subsequent updates
Streaming with SuspenseServer output arrives incrementallyPages with independently loading sections, complex dashboardsImproved perceived performance, faster Time to Interactive

Important Distinction: Server Components vs. Rendering Approaches

It’s crucial to distinguish between Server Components (a React component model) and the rendering approaches (Static, Dynamic, Client-Side, Streaming) we’ve discussed. They are related but not interchangeable:

  • Server Components: These are React components that render exclusively on the server. They have direct access to server-side resources (databases, file system, environment variables) and never send their JavaScript to the client.
  • Rendering Approaches: These describe how the output of your components (whether Server or Client Components) is produced and delivered to the user.

For example, a Server Component can be rendered statically at build time, dynamically on the server at request time, or streamed in chunks. Client Components, on the other hand, are always rendered on the client side after hydration, but their initial HTML might come from a server-side render (SSR or SSG).

Practice Exercise: Optimizing Rendering Strategy

Alright, future Next.js masters! It’s time to put your rendering knowledge into action. For this exercise, imagine you’re building a small Next.js application for a fictional online bookstore. You need to create three distinct pages, each optimized with the most appropriate rendering strategy.

Task 1: The "About Us" Page (Static Rendering)

Create a simple /app/about/page.tsx. This page will contain static information about the bookstore, its mission, and history. It should be highly performant and SEO-friendly.

  • Goal: Ensure this page is statically rendered at build time.
  • Instructions:
    1. Create app/about/page.tsx.
    2. Add some static text and an <h1> tag.
    3. Challenge: How can you explicitly confirm (e.g., in development console or build output if you run next build) that Next.js treats this page as statically rendered? (Hint: Look for output messages related to static generation.)

Task 2: The "Today’s Deals" Page (Dynamic Server Rendering with Data Fetching)

Create a /app/deals/page.tsx that displays a list of "today’s special deals." This data should be fresh for every user request, potentially based on the current time or some other dynamic factor. For this exercise, simulate fetching data from an external API.

  • Goal: Implement dynamic server-side rendering to fetch fresh data on every request.
  • Instructions:
    1. Create app/deals/page.tsx.
    2. Inside your Server Component, simulate fetching data:
    3. // Example of fetching dynamic data
      async function getTodaysDeals() {
        // Simulate API call that returns fresh data each time
        const response = await fetch("https://api.example.com/deals", { cache: "no-store" }); // Important for dynamic!
        if (!response.ok) throw new Error("Failed to fetch deals");
        return response.json();
      }
      export default async function DealsPage() {
        const deals = await getTodaysDeals();
        return (
          <main>
            <h1>Today's Hot Deals!</h1>
            <ul>
              {deals.map((deal: any) => (
                <li key={deal.id}>{deal.name}: ${deal.price}</li>
              ))}
            </ul>
          </main>
        );
      }
      
    4. Observe the network requests in your browser’s developer tools when you refresh this page. What do you notice about the HTML?
    5. Challenge: What would happen if you removed { cache: "no-store" } from the fetch call? (Hint: Next.js has default caching behaviors).

Task 3: The "User Profile Widget" (Client-Side Rendering within a Server Component)

On your bookstore’s homepage (/app/page.tsx), you want to display a small "User Profile" widget. This widget needs to be interactive (e.g., a button to update profile settings) and might rely on browser-specific APIs (like localStorage or window). The rest of the homepage can be server-rendered.

  • Goal: Integrate a client-side rendered component into a server-rendered page.
  • Instructions:
    1. Create a new Client Component file: components/UserProfileWidget.tsx. Make sure to add "use client"; at the top.
    2. Inside UserProfileWidget.tsx, add a simple button and some text. You can optionally try to use localStorage (e.g., to store a username).
    3. // components/UserProfileWidget.tsx
      "use client";
      import { useState, useEffect } from 'react';
      export default function UserProfileWidget() {
        const [username, setUsername] = useState('Guest');
        useEffect(() => {
          // This code runs only on the client-side
          const storedUsername = localStorage.getItem('username');
          if (storedUsername) {
            setUsername(storedUsername);
          }
        }, []);
        const handleUpdateProfile = () => {
          const newName = prompt('Enter your new username:');
          if (newName) {
            localStorage.setItem('username', newName);
            setUsername(newName);
          }
        };
        return (
          <div style={{ border: '1px solid #007bff', padding: '15px', borderRadius: '8px', marginTop: '20px' }}>
            <h3>Hello, {username}!</h3>
            <p>Manage your profile settings.</p>
            <button onClick={handleUpdateProfile} style={{ padding: '8px 15px', backgroundColor: '#007bff', color: 'white', border: 'none', borderRadius: '5px', cursor: 'pointer' }}>
              Update Profile
            </button>
          </div>
        );
      }
      
    4. Import and use this <UserProfileWidget /> in your app/page.tsx (which is a Server Component by default).
    5. Challenge: Try removing "use client"; from UserProfileWidget.tsx. What error do you get, and why? (Hint: Think about where useState and useEffect can run).

Take your time, experiment, and observe the rendering behavior in your browser’s developer tools (Network tab, Elements tab, Console). This hands-on experience is invaluable!

Summary and What’s Next

Fantastic work, FullStackDost! You’ve successfully navigated the intricate world of Next.js rendering. We’ve covered:

  • Client-Side Rendering (CSR): Browser-centric interactivity.
  • Server-Side Rendering (SSR): Server-generated HTML for fast FCP and SEO.
  • Static Rendering (SSG): Pre-built HTML for ultimate performance and caching.
  • Dynamic Rendering: Server-side rendering based on request-time data.
  • Hydration: Bringing server-rendered HTML to life with client-side JavaScript.
  • Streaming and Suspense: Enhancing perceived performance by sending UI chunks incrementally.

Remember, Next.js intelligently decides the best rendering strategy for your application, but as a developer, you have the power to influence and optimize it. The key is to choose the right tool for the right job, balancing performance, data freshness, and interactivity.

Keep practicing these concepts, and you’ll soon be building incredibly efficient and responsive Next.js applications. Up next, we’ll dive deeper into data fetching strategies that complement these rendering patterns. Stay curious, keep coding!

Leave a Reply Cancel reply

You must be logged in to post a comment.

Key features and achitecture
Prev
App Router vs. Pages Router: Navigating Next.js Routing Systems
Next

Copyright © 2026 FullStackDost. All Rights Reserved.

  • Privacy Policy
  • Terms of Service
  • Contact Support

Powered by EduPress