DEV Community

Cover image for ๐ŸŒServer Side Rendering and Client Side Rendering in Next.js
Himanay Khajuria
Himanay Khajuria

Posted on • Edited on

๐ŸŒServer Side Rendering and Client Side Rendering in Next.js

โœจ Introduction

Next.js gives you power to use Server Side Rendering (SSR) and Client Side Rendering (CSR) in the same project.

SSR gives fast ready pages. CSR gives interactive UI.

This blog explains both in a simple project using TypeScript.


๐Ÿ–ฅ๏ธ What is SSR

SSR means the server prepares HTML before sending the page.

This gives

  • โšก Fast first load
  • ๐Ÿ” Better SEO
  • ๐Ÿ“„ Ready content on first paint

Use SSR for content like posts products or anything you want visible right away.


๐Ÿงฉ What is CSR

CSR means the browser updates parts of the page after load.

Use CSR for

  • ๐ŸŽ›๏ธ Buttons
  • ๐Ÿงฎ Counters
  • โœ๏ธ Forms
  • ๐Ÿ”„ Updating UI in real time

๐Ÿ—๏ธ How Next.js decides

  • All components in App Router are server components by default
  • Add use client at the top to make it a client component
  • Client components can use hooks like useState
  • Server components cannot use hooks
  • Client components cannot import server components
  • Use use server for server only logic like database work

๐Ÿค When to use what

Situation Use
SEO and ready content SSR
Interactive UI CSR
Secrets or DB Server code
Static pages SSG

๐Ÿ› ๏ธ Small Next.js Project Example

We build one page

  • Server component fetches posts
  • Client component shows a counter

๐Ÿ“‚ Folder structure

my-next-app/
  app/
    page.tsx
    components/
      PostsList.tsx
      Counter.tsx
    actions.ts
  package.json
  tsconfig.json
Enter fullscreen mode Exit fullscreen mode

๐Ÿ“„ 1. Server Component Page

File: app/page.tsx

import PostsList from './components/PostsList'
import Counter from './components/Counter'

export default async function Page() {
  return (
    <main>
      <h1>Server and Client Rendering Demo</h1>
      <PostsList />
      <hr />
      <Counter />
    </main>
  )
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿ’ก Explanation

  • This file is a Server Component
  • It loads data on the server
  • It imports a client component and renders both together
  • HTML for posts is ready before load

๐Ÿ“„ 2. Server Component for SSR

File: app/components/PostsList.tsx

async function fetchPosts() {
  const res = await fetch('https://jsonplaceholder.typicode.com/posts')
  return res.json()
}

export default async function PostsList() {
  const posts = await fetchPosts()

  return (
    <ul>
      {posts.slice(0, 5).map(post => (
        <li key={post.id}>
          <strong>{post.title}</strong>
          <p>{post.body}</p>
        </li>
      ))}
    </ul>
  )
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿ’ก Explanation

  • No use client means it is server only
  • Data is fetched directly on the server
  • Fast and SEO friendly
  • The browser receives the ready HTML

๐Ÿ“„ 3. Client Component for CSR

File: app/components/Counter.tsx

'use client'
import { useState } from 'react'

export default function Counter() {
  const [count, setCount] = useState(0)

  return (
    <div>
      <p>Count {count}</p>
      <button onClick={() => setCount(c => c + 1)}>Add</button>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿ’ก Explanation

  • use client tells Next.js this runs in the browser
  • It uses useState so it must run on the client
  • The UI updates without page reload

๐Ÿ“„ 4. Server Only Logic

File: app/actions.ts

'use server'

export async function addPost(data: { title: string; body: string }) {
  // safe server side logic
  return { ok: true }
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿ’ก Explanation

  • Code stays on the server
  • Good for DB or secret work
  • Never sent to the browser

๐Ÿ“„ 5. Pages Router SSR Example (optional)

File: pages/index.tsx

import type { GetServerSideProps } from 'next'
import { useState } from 'react'

export default function Home({ posts }) {
  const [count, setCount] = useState(0)

  return (
    <main>
      <h1>SSR with Pages Router</h1>
      <ul>
        {posts.map(p => (
          <li key={p.id}>{p.title}</li>
        ))}
      </ul>
      <p>Local count {count}</p>
      <button onClick={() => setCount(v => v + 1)}>Add</button>
    </main>
  )
}

export const getServerSideProps: GetServerSideProps = async () => {
  const res = await fetch('https://jsonplaceholder.typicode.com/posts')
  const posts = await res.json()
  return { props: { posts: posts.slice(0, 5) } }
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿ’ก Explanation

  • getServerSideProps runs on every request
  • Server returns the posts as props
  • UI state still works with client hooks

๐Ÿงญ How to separate code correctly

โœ” Server code

  • Use for API calls
  • Use for DB logic
  • No hooks
  • Can fetch data safely

โœ” Client code

  • For UI events
  • For interactive features
  • Needs use client

โœ” Import rules

  • Server can import client
  • Client cannot import server

๐Ÿ“ Checklist

  • Need SEO? โญ Server
  • Need state or events? โญ Client
  • Using secrets? โญ Server
  • Want fast UI updates? โญ Client

๐Ÿšถ Step by step workflow

  1. Create a Next.js app
  2. Build server component for data
  3. Build client component for UI
  4. Combine them inside page
  5. Test SSR by turning off JS
  6. Test CSR by clicking the counter
  7. Improve step by step

โ“ FAQ

Q. Can server components use hooks?

No

Q. Can client components fetch data?

Yes

Q. Does server code ship to browser?

No


๐ŸŽ‰ Final Thoughts

  • Next.js makes it simple to mix SSR and CSR in one project
  • Use SSR for speed and SEO
  • Use CSR for interaction
  • Keep your code clean and split server and client logic
  • You will build faster and better apps this way

Top comments (0)