TL;DR
- SSR is on by default and always runs, regardless of the
"use client"
directive. - The
"use client"
directive (an RSC feature) only controls whether the JS bundle (and hydration) for that component is sent or not. SSR‑generated HTML is still always delivered. -
Hooks skipped during SSR: In client components (
"use client"
), hooks likeuseEffect
don’t execute on the server—so any UI you render based on state manipulation in hooks (e.g. displaying
only after a fetch inData loadeduseEffect
) won’t be included in the initial HTML, which can impact SEO. - RSCs can be async (you can call APIs directly in the component); client components (
"use client"
) behave like normal React components in the browser.
Scroll to bottom for demo examples 👇
Server‑Side Rendering (SSR)
Server‑Side Rendering (SSR) generates HTML on each request by executing your React components on the server before sending it to the browser. (Rendering in Next.js)
- Every request is fresh: HTML is rebuilt on each incoming request, ensuring up‑to‑date data.
-
Server‑only environment: Runs in Node.js on the server—no access to browser APIs like
window
ordocument
. -
Independent of
"use client"
: Components are SSR’d whether or not you mark them with"use client"
; that directive only controls bundling, not where rendering happens. -
Always ships HTML: Even client components get pre‑rendered to HTML on the server, then their JS bundle is sent for hydration if
"use client"
is used. -
Async/Await support: You can freely use
async
functions in your page components (e.g.,fetch
data) and have them await before sending HTML.
// app/dashboard/page.tsx (SSR by default)
export default async function DashboardPage() {
const res = await fetch('https://api.example.com/data');
const data = await res.json();
return <h1>Welcome back, {data.user.name}!h1>;
}
React Server Components (RSC)
React Server Components (RSC) are components that execute only on the server and are the default component type in Next.js’s App Router. (RSC in Next.js) ("use client"
directive)
-
No hooks or browser APIs: Cannot use
useState
,useEffect
, or event handlers, since they never run in the browser. (Client Components) - Zero JS bundle by default: Only HTML and a serialized data payload are sent to the client—no extra JavaScript. (React)
-
Compose with Client Components: To add interactivity, import or wrap a Client Component (marked with
"use client"
) inside your RSC. - Streaming support: Can stream partial HTML to the browser as data resolves, improving Time to First Byte (TTFB). (Loading UI and Streaming)
// app/Weather.tsx (RSC by default)
export default async function Weather() {
const weather = await getWeatherFor('London');
return <div>Current temp: {weather.temp}°Cdiv>;
}
// app/WeatherClient.tsx (Client Component)
'use client';
import { useState } from 'react';
export default function WeatherClient({ temp }: { temp: number }) {
const [unit, setUnit] = useState<'C'|'F'>('C');
const display = unit === 'C' ? `${temp}°C` : `${Math.round(temp * 9/5 + 32)}°F`;
return <button onClick={() => setUnit(unit === 'C' ? 'F' : 'C')}>{display}button>;
}
Demo examples
1 . SSR in RSC
// page.tsx
import Welcome from "./Welcome"
export default async function Home() {
console.log("Page file: Welcome to the app!")
return <Welcome />
}
//Welcome.tsx
const Welcome = () => {
console.log("Welcome file: Welcome to the app!")
return (
<section>
<h1>Welcome to the App!h1>
<p>This is a simple React application.p>
<p>Feel free to explore the features and functionalities.p>
section>
)
}
export default Welcome
- Output
2 . SSR in RSC with async API call
// page.tsx
import Welcome from "./Welcome"
export default async function Home() {
console.log("Page file: Welcome to the app!")
return <Welcome />
}
//Welcome.tsx
const Welcome = async () => {
console.log("Welcome file: Welcome to the app!")
// fetch data from an API
const response = await fetch("https://jsonplaceholder.typicode.com/posts/1")
const data = await response.json()
console.log("Data fetched from API:", data)
return (
<section>
<h1>Welcome to the App!h1>
<p>This is a simple React application.p>
<p>Feel free to explore the features and functionalities.p>
section>
)
}
export default Welcome
Output
Note: For the above two examples with Server Side Components, you can see in the below output that JavaScript is disabled (disabled only for the below output) and the DOM contains the tags, which came from SSR as client side rendering is disabled. Also, in the above output screenshots, there's no console log in client side, that simply means, since these are RSC components, there JavaScript is not sent in the bundle to client, improving efficiency.
3 . SSR in RCC (Client Side Component)
// page.tsx
import Welcome from "./Welcome"
export default async function Home() {
console.log("Page file: Welcome to the app!")
return <Welcome />
}
"use client"
//Welcome.tsx
const Welcome = () => {
console.log("Welcome file: Welcome to the app!")
return (
<section>
<h1>Welcome to the App!h1>
<p>This is a simple React application.p>
<p>Feel free to explore the features and functionalities.p>
section>
)
}
export default Welcome
- Output
- Output of the same code when client side JavaScript is disabled (No client side rendering). This is the validation that client side components still get SSR rendered.
4 . SSR in RCC (Client Side Component) with hooks
// page.tsx
import Welcome from "./Welcome"
export default async function Home() {
console.log("Page file: Welcome to the app!")
return <Welcome />
}
"use client"
//Welcome.tsx
import { useEffect, useState } from "react"
const Welcome = () => {
console.log("Welcome file: Welcome to the app!")
const [isUIVisible, setShowUI] = useState<boolean>(false)
useEffect(() => {
setShowUI(true)
}, [])
if (!isUIVisible) {
return <div>Loading...div>
}
return (
<section>
<h1>Welcome to the App!h1>
<p>This is a simple React application.p>
<p>Feel free to explore the features and functionalities.p>
section>
)
}
export default Welcome
- Output, appears after showing "Loading..." for an instance.
- Output of the same code when javascript is blocked. This is where SSR and SEO will not work out for projects where UI rendering logic depends on React hooks.
Happy hacking! 🚀