Core Rendering Patterns for Web Apps
In this article, you will find;
- Client-Side Rendering (CSR).
- Server-Side Rendering (SSR).
- Static Site Generation (SSG).
- React Server Components (RSC).
Client-Side Rendering (CSR)
Client-Side Rendering (CSR) is a rendering approach where the server sends a minimal HTML file to the client, usually just a <div>
or a container element, along with a JavaScript bundle. The actual rendering of the user interface happens in the browser after JavaScript is executed. This allows the browser to dynamically fetch data and render the application on the client side.
How It Works
- Initial Request: The browser sends a request to the server and receives a minimal HTML file with a link to the JavaScript bundle.
- JavaScript Execution: The browser downloads and executes the JavaScript code. This often includes the app’s framework or library (like React).
- Fetching Data: If the app requires additional data (from an API), it fetches it dynamically after the JavaScript is loaded.
- Rendering UI: The UI is rendered in the browser using the data and JavaScript logic.
When to Use CSR
- Dynamic Applications: Ideal for Single-Page Applications (SPAs) where user interaction is critical, such as dashboards, chat applications, or social media platforms.
- SEO is Less Critical: CSR is less SEO-friendly because search engine crawlers may not execute JavaScript to see the content.
- Interactive and Stateful UIs: When the app has components that require real-time updates or high interactivity.
Server-Side Rendering (SSR)
Server-Side Rendering (SSR) is a rendering technique where HTML is generated dynamically on the server for every request. The server fetches data, builds the HTML, and sends a fully rendered page to the browser. Once the page is loaded, JavaScript takes over to enable interactivity.
How It Works
- Browser Request: The browser sends a request to the server for a specific page.
- Server Processing: The server fetches the necessary data and uses it to render the page.
- HTML Response: A fully-rendered HTML page is sent back to the browser.
- Client Hydration: JavaScript “hydrates” the page, enabling interactivity.
When to Use SSR
- Dynamic Data: When content changes frequently and needs to reflect real-time data (stock prices, social media feeds).
- SEO Priority: For pages that need high search engine visibility, as fully-rendered HTML is easier for crawlers to index.
- First-Load Speed: Ideal for improving perceived performance by sending complete HTML to users quickly.
Static Site Generation (SSG)
Static Site Generation (SSG) is a rendering method where HTML pages are pre-rendered at build time. These pages are generated once, stored as static files, and served directly to users via a Content Delivery Network (CDN). Since the HTML is pre-built, SSG delivers blazing-fast performance and excellent SEO while minimizing server overhead.
How It Works
- Build Process: During the build phase (with
npm run build
), the framework fetches all necessary data and generates static HTML files. Each page’s HTML file is written to the filesystem for deployment. - Deployment: The pre-generated HTML files are uploaded to a CDN or web server.
- Client Request: When a user requests a page, the static HTML file is served instantly, without server-side rendering.
- Client Hydration (Optional): If the app uses React, Vue, or similar frameworks, JavaScript can hydrate the static HTML to add interactivity.
When to Use SSG
- Static Content: Use SSG when the content doesn’t change often, such as blogs, marketing pages, or documentation.
- Performance-First Applications: For high-traffic sites where speed is critical, SSG delivers fast load times by leveraging CDNs.
- SEO-Critical Pages: SSG ensures that search engines can index fully-rendered HTML, making it ideal for SEO. Both Server-Side Rendering (SSR) and Static Site Generation (SSG) are excellent for SEO because they deliver fully-rendered HTML to search engine crawlers.
How SSG Works in React and Next.js
React 19:
- React itself does not support SSG natively, even in version 19. It is a library for client-side rendering and lacks the tools to pre-generate HTML files at build time.
- For SSG, React relies on frameworks like Next.js, Gatsby, or Astro, which handle build-time rendering and static page generation.
Next.js 15:
- Next.js supports SSG for every page by default, but the approach varies depending on whether data fetching is needed.
- Next.js supports Static Site Generation (SSG) but does not enable it automatically.
- You must define a
getStaticProps
function in your page to fetch data and enable SSG. - Without
getStaticProps
, Next.js defaults to CSR for the page.
// pages/about.js
export default function AboutPage() {
return (
<div>
<h1>About Us</h1>
<p>This page is pre-rendered automatically by Next.js.</p>
</div>
);
}
export async function getStaticProps() {
const data = await fetch('https://api.example.com/data').then((res) => res.json());
return {
props: { data },
};
}
export default function PageWithData({ data }) {
return (
<div>
<h1>Static Site Generation with Data</h1>
<p>{data.message}</p>
</div>
);
}
React Server Components (RSC)
React Server Components (RSC) are a new feature in React designed to render components on the server and stream their output to the client. Unlike traditional Server-Side Rendering (SSR), RSC allows components to run partially on the server, enabling efficient rendering while reducing the amount of JavaScript sent to the browser.
You can use React Server Components (RSC) in plain React, but it’s not straightforward or out-of-the-box (You’d need to create a custom setup using tools like Express or Fastify). RSC is primarily designed to work with frameworks like Next.js(13+ with the app
directory), which provide the tooling and server infrastructure needed to make RSC practical and easy to use.
How RSC Works
- Server Execution: Certain components are marked as server components. These components are rendered on the server, which fetches any required data and processes them.
- Streaming HTML/JSON to Client: The rendered output of server components is streamed to the client as serialized data.
- Client-Side Integration: On the client, React “assembles” the server-rendered output and merges it with interactive client-side components.
When to Use RSC
- Large Applications: Where reducing JavaScript bundle size is critical for performance.
- SEO-Critical Pages: Server components allow SEO-ready content to be streamed incrementally, improving crawlability.
- Frequent Data Updates: Content that depends on server-side data but doesn’t need constant rehydration or user interaction.
- Hybrid Pages: When parts of the UI are static or server-dependent and others are interactive.
Key Differences Between SSR and RSC
Timing of Rendering:
- SSR: The entire page is rendered dynamically on the server at runtime for every user request.
- RSC: Components are rendered on the server at runtime, but only specific server components, not the entire page.
Data Fetching:
- SSR: Fetches all required data on the server for the entire page on every request.
- RSC: Fetches data only for server components and allows seamless mixing with client components for interactive parts.
Client-Side JavaScript:
- SSR: Sends fully server-rendered HTML but requires hydration on the client, meaning all JavaScript for the page must still be loaded.
- RSC: Sends minimal JavaScript to the client since server components don’t include client-side logic.
Streaming:
- SSR: Typically streams the entire HTML output for the page.
- RSC: Streams components incrementally, enabling faster perceived load times by delivering visible content first.
Use Cases:
- SSR: Best for fully dynamic content that needs real-time updates or personalized experiences ( dashboards, search results).
- RSC: Ideal for hybrid content that mixes static and dynamic parts while reducing client-side JavaScript for better performance.
Page Component (HomePage)
// app/page.jsx
import FruitsList from './FruitsList'; // Import the Server Component
export default function HomePage() {
return (
<div>
<h1>React Server Components Example</h1>
<FruitsList /> {/* Render the Server Component */}
</div>
);
}
Server Component (FruitsList)
// app/FruitsList.jsx
async function fetchFruits() {
const response = await fetch('https://api.example.com/fruits', {
cache: 'no-store', // Fetch fresh data every time
});
if (!response.ok) {
throw new Error(`Failed to fetch fruits: ${response.status}`);
}
return response.json();
}
// This is a Server Component by default
export default async function FruitsList() {
const fruits = await fetchFruits(); // Data fetched on the server
return (
<ul>
{fruits.map((fruit) => (
<li key={fruit.id}>
{fruit.name} - {fruit.color}
</li>
))}
</ul>
);
}
Finally;
Client-Side Rendering (CSR): Rendering happens entirely in the browser. Ideal for highly interactive apps but may suffer from slower SEO and initial load.Server-Side Rendering (SSR): The entire page is rendered dynamically on the server for each request. Great for SEO and real-time dynamic content but comes with higher server costs.
Static Site Generation (SSG): Pages are pre-rendered at build time and served as static files. Fast and scalable for static or rarely updated content.
React Server Components (RSC): A hybrid approach allowing server-side rendering of specific components. Reduces client-side JavaScript and improves performance for dynamic content.
That was all about Core Rendering Patterns for Web Apps.
As I come across different and interesting topics about web development, I will keep continuing to come up with different stories.