Server-Side Rendering (SSR)

Rendering pages on the server for every request

⚡ What is Server-Side Rendering?

SSR generates HTML on the server for each request, ensuring users always see fresh content. This approach is perfect for dynamic data that changes frequently, providing better SEO and faster initial page loads with up-to-date information.


// Server Component (default in Next.js)
async function getData() {
  const res = await fetch('https://api.example.com/data')
  return res.json()
}
                                    

SSR Concepts

Server-Side Rendering happens on every request, making it ideal for personalized or frequently updated content. Next.js App Router uses Server Components by default, automatically rendering on the server. This provides SEO benefits and fast initial loads while keeping data fresh.

🔄

Fresh Data

Always up-to-date content

// Fetches on every request
await fetch(url)
🔍

SEO Friendly

Fully rendered HTML for crawlers

// Search engines see content
<h1>{data.title}</h1>
👤

Personalized

User-specific content

// Different for each user
const user = await getUser()

Fast Initial Load

No client-side data fetching

// HTML ready immediately
return <Page data={data} />

🔹 Basic SSR Example

Server Components fetch data automatically on each request:

// app/posts/page.js
async function getPosts() {
  const res = await fetch('https://api.example.com/posts', {
    cache: 'no-store' // Disable caching for SSR
  })
  return res.json()
}

export default async function PostsPage() {
  const posts = await getPosts()
  
  return (
    <div>
      <h1>Latest Posts</h1>
      {posts.map(post => (
        <article key={post.id}>
          <h2>{post.title}</h2>
          <p>{post.excerpt}</p>
        </article>
      ))}
    </div>
  )
}

Rendered on every request:

Latest Posts

Getting Started with Next.js

Learn the basics of Next.js framework...

Understanding SSR

Deep dive into server-side rendering...

🔹 Dynamic SSR with Parameters

Fetch data based on URL parameters for dynamic pages:

🔸 User Profile Example

// app/user/[id]/page.js
async function getUser(id) {
  const res = await fetch(`https://api.example.com/users/${id}`, {
    cache: 'no-store'
  })
  return res.json()
}

export default async function UserPage({ params }) {
  const user = await getUser(params.id)
  
  return (
    <div>
      <h1>{user.name}</h1>
      <p>Email: {user.email}</p>
      <p>Joined: {user.joinDate}</p>
    </div>
  )
}

For URL: /user/123

John Doe

Email: [email protected]

Joined: January 15, 2024

🔹 Disabling Cache for SSR

Ensure fresh data on every request with cache options:

🔸 Method 1: Fetch Options

// Disable caching in fetch
const res = await fetch(url, {
  cache: 'no-store'
})

🔸 Method 2: Revalidate Time

// Revalidate every request
const res = await fetch(url, {
  next: { revalidate: 0 }
})

🔸 Method 3: Route Segment Config

// app/page.js
export const dynamic = 'force-dynamic'

export default async function Page() {
  // All fetches will be dynamic
}

🔹 SSR with Headers and Cookies

Access request data for personalized content:

// app/dashboard/page.js
import { cookies, headers } from 'next/headers'

export default async function Dashboard() {
  const cookieStore = cookies()
  const token = cookieStore.get('auth-token')
  
  const headersList = headers()
  const userAgent = headersList.get('user-agent')
  
  const userData = await fetch('https://api.example.com/user', {
    headers: {
      'Authorization': `Bearer ${token?.value}`
    },
    cache: 'no-store'
  })
  
  return (
    <div>
      <h1>Welcome back!</h1>
      <p>Your personalized dashboard</p>
    </div>
  )
}

🔹 When to Use SSR

Choose SSR for specific use cases:

✅ Good for SSR:

  • Real-time data: Stock prices, news feeds
  • Personalized content: User dashboards, recommendations
  • Authentication: Protected pages with user data
  • Frequently updated: Content that changes often

❌ Not ideal for SSR:

  • Static content: About pages, documentation
  • High traffic: Can be slower than static pages
  • Rarely changes: Blog posts, marketing pages

🔹 SSR Performance Tips

Optimize your server-side rendering:

  • Parallel fetching: Use Promise.all() for multiple requests
  • Streaming: Use loading.js for instant feedback
  • Selective SSR: Only fetch what you need
  • Database optimization: Use indexes and efficient queries
  • Consider ISR: For semi-static content
// Parallel data fetching
export default async function Page() {
  const [posts, users] = await Promise.all([
    getPosts(),
    getUsers()
  ])
  
  return <div>...</div>
}

🧠 Test Your Knowledge

When does SSR generate HTML?