Page Router vs. App Router vs. React Server Components
As the React ecosystem evolves, Next.js offers developers a variety of rendering options. Notably, these include Next.js’s Page Router SSR (Server-Side Rendering) and React Server Components (RSC). In this article, let’s explore the differences between traditional Next.js Page Router-based SSR, Next.js App Router-based SSR, and React Server Components.
Is a Next.js App Router Server Component the Same as a React Server Component?
To get straight to the point, the Server Components in the Next.js App Router are built upon React’s Server Components. Next.js adopted the core ideas designed by the React team for Server Components and quickly implemented a corresponding ecosystem through the App Router.
However, the SSR in the Page Router is a bit different. This is because it was Next.js’s proprietary technology developed to enable the use of React with SSR before React Server Components were introduced. 🤔
Alright, let’s take a look at the Page Router first!
SSR Based on the Next.js Page Router
In the Next.js Page Router, SSR is implemented using a method called getServerSideProps. This method is responsible for fetching data on the server at the time of a page request. This allows users to receive HTML rendered with the latest data, which is useful for projects where SEO optimization and dynamic data handling are important.
The main characteristic of SSR in the Page Router is page-level data fetching and processing. Each page is designed to fetch and render data independently, which clearly separates the configuration from the data-fetching logic. However, a downside is that since every page request involves preprocessing on the server, it can increase server load in high-traffic applications.
Let’s look at an example. Below is a basic SSR implementation using getServerSideProps:
export async function getServerSideProps(context) {
const res = await fetch('https://api.example.com/data');
const data = await res.json();
return {
props: { data },
};
}
export default function Page({ data }) {
return <div>{data.title}</div>;
}
In the code above, data is fetched on the server when the page loads, and this data is sent to the client as HTML. As you can see, Page Router-based SSR provides a clear data flow and an SEO-friendly architecture.
Next.js App Router and React Server Components
With the introduction of the App Router in Next.js 13, it became possible to use React Server Components (RSC) by default. RSC aims to optimize application performance by more effectively defining the boundary between the client and server. App Router-based SSR offers a more granular, component-centric approach than the traditional Page Router.
The App Router provides flexibility in data fetching and rendering, allowing specific components to be rendered on the server while others are handled on the client. This approach helps reduce initial load times and efficiently distributes the server’s computational load. RSC combines React’s philosophy of declarative UI with server-centric rendering, enabling developers to maximize both client and server performance.
The main advantages of RSC are:
- Component-level data fetching: Reduces traffic costs by fetching only necessary data from the server.
- Reduced client bundle size: Eliminates unnecessary client-side JavaScript.
- Flexible state management: Allows for efficient state sharing between the client and server.
In the next section, we’ll explore coding patterns for using the App Router and RSC, as well as practical issues to consider.
Next.js Page Router SSR vs. App Router SSR
Next.js offers two core routing methods: the Page Router (the traditional way) and the App Router (based on React Server Components). Both support SSR, but their operating principles and philosophies are completely different.
1. Page Router-Based SSR
The Page Router is Next.js’s traditional routing method, which primarily supports server-side rendering through getServerSideProps. This approach renders React components into HTML on the server, sends it to the client, and then enables interactivity through a process called hydration.
Features and How It Works
- Data Fetching: Uses
getServerSidePropsto pre-fetch data on the server. - HTML Rendering: Converts React components into an HTML string on the server.
- Hydration: JavaScript on the client activates event handlers and state.
- SEO-Friendly: Makes HTML content immediately accessible to search engine crawlers.
// Example of Page Router-based SSR
export async function getServerSideProps() {
const data = await fetch('https://api.example.com/data');
return {
props: { data },
};
}
export default function Page({ data }) {
return <div>{data.title}</div>;
}
Limitations
- Increased Bundle Size: Since all JavaScript is sent to the client, initial loading speed can be slow.
- Complex Data Flow: Data fetching logic is located outside the component, which can reduce readability.
2. App Router-Based SSR (Utilizing React Server Components)
Introduced in Next.js 13, the App Router is designed around React Server Components and offers a completely different approach to SSR. It leverages RSC to efficiently separate components that run only on the server from those that run on the client.
Features and How It Works
- Leverages React Server Components: Renders server-only components into a serialized format called the RSC Payload instead of HTML.
- Client Boundary: Explicitly declares client components using the
'use client'directive. - Bundle Size Optimization: Server-only logic is not sent to the client, resulting in a smaller JavaScript bundle.
- Progressive Streaming: Improves initial load speed by streaming server-rendered content in chunks.
// Example of App Router-based SSR
// app/page.js (Server Component)
export default async function Page() {
const data = await fetch('https://api.example.com/data');
return <div>{data.title}</div>;
}
// components/Button.js (Client Component)
'use client';
export default function Button() {
return <button>Click Me</button>;
}
Advantages
- Performance Optimization: Minimizes the client’s JavaScript load through server-only components.
- Simplified Data Fetching: Components can fetch data directly themselves.
- Progressive Rendering: Enhances user experience by rendering content as data arrives.
Limitations
- Learning Curve: It’s a new paradigm for developers accustomed to the Page Router.
- Limited Client State Management: State management hooks (
useState,useEffect) cannot be used within Server Components.
React Server Components (RSC)
React Server Components are a new concept introduced in React 18 and form the core foundation of the Next.js App Router. RSCs define components that run exclusively on the server, sending the component’s resulting data to the client in a serialized format.
Features of RSC
- Server-Only Execution: The component renders only on the server and is not sent to the client.
- Stateless: Cannot use state management hooks, focusing on pure rendering logic.
- Direct Data Fetching: Can directly access resources like databases and file systems.
// Example of a React Server Component
async function Post({ id }) {
const post = await fetch(`https://api.example.com/posts/${id}`);
return <div>{post.title}</div>;
}
Strengths of RSC
- Reduced Bundle Size: Server-only code is excluded from the client bundle.
- Simplified Data Access: Can access data sources directly without a separate API layer.
- Streaming Support: Allows for progressive rendering of large pages.
Personal Opinion and Conclusion
I believe the reason Next.js continues to be the number one full-stack web framework in 2025 is due to its agility and practicality in technological innovation. Continuous updates that keep pace with fast-changing IT trends, the provision of practical, real-world features, and a philosophy that maximizes development productivity have combined to establish it as a framework that many developers trust and choose!