development

SSR vs CSR: Der komplette Guide für die richtige Wahl 2025

Server-Side vs. Client-Side Rendering verstehen: Vor- und Nachteile, Use Cases, Performance-Impact und wann Sie welche Strategie nutzen sollten.

Onur Cirakoglu
11 min read
#SSR#CSR#Next.js#React#Architecture#Performance
Server-Side und Client-Side Rendering Architektur Diagramm

Die Entscheidung zwischen Server-Side Rendering (SSR) und Client-Side Rendering (CSR) ist fundamental für jede moderne Web-Anwendung. In diesem Guide erklären wir beide Ansätze, ihre Vor- und Nachteile sowie wann Sie welche Strategie wählen sollten.

Was ist Server-Side Rendering (SSR)?

Bei SSR wird HTML auf dem Server generiert und als fertige Seite an den Browser gesendet:

// Next.js Server Component (SSR)
export default async function BlogPost({ params }) {
  // Läuft auf dem Server
  const post = await db.post.findUnique({
    where: { slug: params.slug }
  })
 
  // HTML wird server-side generiert
  return (
    <article>
      <h1>{post.title}</h1>
      <div>{post.content}</div>
    </article>
  )
}

Ablauf:

  1. User request → Server
  2. Server lädt Daten aus DB
  3. Server rendert HTML
  4. HTML wird an Browser gesendet
  5. Browser zeigt Seite sofort
  6. JavaScript hydrated die Seite

Was ist Client-Side Rendering (CSR)?

Bei CSR sendet der Server nur ein minimales HTML + JavaScript-Bundle, das dann im Browser die Seite rendert:

// React Client Component (CSR)
'use client'
 
export default function BlogPost({ slug }) {
  const [post, setPost] = useState(null)
  const [loading, setLoading] = useState(true)
 
  useEffect(() => {
    // Läuft im Browser
    fetch(`/api/posts/${slug}`)
      .then(r => r.json())
      .then(data => {
        setPost(data)
        setLoading(false)
      })
  }, [slug])
 
  if (loading) return <div>Loading...</div>
 
  return (
    <article>
      <h1>{post.title}</h1>
      <div>{post.content}</div>
    </article>
  )
}

Ablauf:

  1. User request → Server
  2. Server sendet leeres HTML + JS-Bundle
  3. Browser lädt JavaScript
  4. JavaScript führt fetch() aus
  5. Daten kommen von API
  6. React rendert UI im Browser

Der direkte Vergleich

| Kriterium | SSR | CSR | |-----------|-----|-----| | Initial Load | ⚡ Sehr schnell | 🐌 Langsamer | | SEO | ✅ Exzellent | ⚠️ Eingeschränkt | | Time to Interactive | ⏱️ Mittel | ⚡ Schnell nach Load | | Server Load | ❌ Höher | ✅ Niedriger | | Bundle Size | ✅ Kleiner | ❌ Größer | | Navigation | 🔄 Page Reload | ⚡ Instant | | Real-time Updates | ❌ Schwierig | ✅ Einfach | | Offline Support | ❌ Nicht möglich | ✅ Mit PWA möglich |

Detaillierte Performance-Analyse

SSR Performance-Metriken

// Typical SSR Timings
Server Processing: 50-200ms
Network Transfer: 100-300ms
HTML Parsing: 50-100ms
Hydration: 200-500ms
 
Total Time to Interactive: 400-1100ms

Vorteile:

  • First Contentful Paint (FCP): 0.3-0.8s
  • Largest Contentful Paint (LCP): 0.5-1.2s
  • SEO-freundlich: Crawler sehen vollständiges HTML

Nachteile:

  • Server muss bei jedem Request rendern
  • Höhere Server-Kosten
  • Längere Time to Interactive (TTI)

CSR Performance-Metriken

// Typical CSR Timings
Initial HTML: 20-50ms
JavaScript Download: 500-2000ms
JavaScript Parse: 200-800ms
API Calls: 200-500ms
Rendering: 100-300ms
 
Total Time to Interactive: 1000-3600ms

Vorteile:

  • Nach initial load: Instant Navigation
  • Niedrigere Server-Kosten
  • Einfachere Real-time Features

Nachteile:

  • Langsamer Initial Load
  • SEO-Herausforderungen
  • Größere Bundle-Größen

SSR Use Cases

1. Content-Heavy Websites

Blogs, News, Marketing-Sites:

// app/blog/[slug]/page.tsx
export default async function BlogPost({ params }) {
  const post = await getPost(params.slug)
 
  return (
    <>
      {/* SEO-kritischer Content */}
      <article>
        <h1>{post.title}</h1>
        <meta name="description" content={post.excerpt} />
        <div dangerouslySetInnerHTML={{ __html: post.content }} />
      </article>
 
      {/* Interaktive Elemente als Client Component */}
      <CommentSection postId={post.id} />
    </>
  )
}

Warum SSR?

  • ✅ Besseres SEO-Ranking
  • ✅ Social Media Previews funktionieren
  • ✅ Schnellerer First Paint
  • ✅ Accessibility (funktioniert auch ohne JS)

2. E-Commerce Product Pages

export default async function ProductPage({ params }) {
  const product = await db.product.findUnique({
    where: { slug: params.slug },
    include: { reviews: true, variants: true }
  })
 
  return (
    <div>
      {/* SSR für SEO */}
      <ProductDetails product={product} />
      <Reviews reviews={product.reviews} />
 
      {/* CSR für Interaktivität */}
      <AddToCartButton productId={product.id} />
      <ImageGallery images={product.images} />
    </div>
  )
}

Warum SSR?

  • ✅ Google Shopping Integration
  • ✅ Product Schema für Rich Snippets
  • ✅ Schnellere Conversion (User sieht Product sofort)

3. Dashboard Landing Pages

export default async function DashboardHome() {
  const stats = await getOverviewStats()
 
  return (
    <div>
      {/* SSR für initial stats */}
      <StatsOverview data={stats} />
 
      {/* CSR für interaktive Charts */}
      <Suspense fallback={<ChartSkeleton />}>
        <InteractiveChart />
      </Suspense>
    </div>
  )
}

Mehr dazu in unserem Next.js 15 Guide.

CSR Use Cases

1. Interactive Dashboards

Admin Panels, Analytics Tools:

'use client'
 
export default function AnalyticsDashboard() {
  const [dateRange, setDateRange] = useState('7d')
  const [data, setData] = useState([])
 
  // Real-time Updates
  useEffect(() => {
    const ws = new WebSocket('wss://api.example.com/analytics')
    ws.onmessage = (event) => {
      setData(prev => [...prev, JSON.parse(event.data)])
    }
    return () => ws.close()
  }, [])
 
  return (
    <div>
      <DateRangeSelector value={dateRange} onChange={setDateRange} />
      <LiveChart data={data} />
      <MetricsGrid data={data} />
    </div>
  )
}

Warum CSR?

  • ✅ Real-time WebSocket-Updates
  • ✅ Komplexe Interaktionen
  • ✅ Kein SEO nötig (behind login)
  • ✅ State-intensive UI

2. Single Page Applications (SPA)

Gmail, Trello, Figma-artige Apps:

'use client'
 
export default function EmailClient() {
  const [emails, setEmails] = useState([])
  const [selectedEmail, setSelectedEmail] = useState(null)
  const [folders, setFolders] = useState([])
 
  // Komplexe Client-State
  const handleDragDrop = (emailId, folderId) => {
    // Optimistic Update
    setEmails(prev => prev.map(e =>
      e.id === emailId ? { ...e, folderId } : e
    ))
 
    // API Call im Hintergrund
    api.moveEmail(emailId, folderId)
  }
 
  return (
    <div className="flex h-screen">
      <Sidebar folders={folders} />
      <EmailList emails={emails} onSelect={setSelectedEmail} />
      <EmailViewer email={selectedEmail} />
    </div>
  )
}

Warum CSR?

  • ✅ App-like Experience
  • ✅ Drag & Drop, Keyboard Shortcuts
  • ✅ Offline-first möglich
  • ✅ Instant Navigation

3. Tools & Calculators

'use client'
 
export default function MortgageCalculator() {
  const [principal, setPrincipal] = useState(200000)
  const [rate, setRate] = useState(3.5)
  const [years, setYears] = useState(30)
 
  // Berechnung client-side (kein Server benötigt)
  const monthlyPayment = useMemo(() => {
    const monthlyRate = rate / 100 / 12
    const numPayments = years * 12
    return principal * monthlyRate * Math.pow(1 + monthlyRate, numPayments) /
           (Math.pow(1 + monthlyRate, numPayments) - 1)
  }, [principal, rate, years])
 
  return (
    <div>
      <Slider value={principal} onChange={setPrincipal} />
      <Slider value={rate} onChange={setRate} />
      <Slider value={years} onChange={setYears} />
      <Result value={monthlyPayment} />
    </div>
  )
}

Hybrid: Das Beste aus beiden Welten

Next.js App Router Strategie

Modern ist weder pure SSR noch pure CSR, sondern eine intelligente Mischung:

// app/products/[id]/page.tsx - Server Component
export default async function ProductPage({ params }) {
  // SSR für SEO-kritischen Content
  const product = await getProduct(params.id)
 
  return (
    <div>
      {/* Server-rendered */}
      <ProductHero product={product} />
      <ProductDescription description={product.description} />
 
      {/* Client-rendered für Interaktivität */}
      <ProductGallery images={product.images} />
      <AddToCart productId={product.id} />
 
      {/* Lazy-loaded */}
      <Suspense fallback={<ReviewsSkeleton />}>
        <Reviews productId={product.id} />
      </Suspense>
    </div>
  )
}

Partial Prerendering (PPR)

Next.js 15 führt PPR ein - das ultimative Hybrid:

// Partial Prerendering aktivieren
export const experimental_ppr = true
 
export default function Dashboard() {
  return (
    <div>
      {/* Static - instantly visible */}
      <Header />
      <Sidebar />
 
      {/* Dynamic - streams in */}
      <Suspense fallback={<Skeleton />}>
        <UserSpecificContent />
      </Suspense>
 
      {/* Static - instantly visible */}
      <Footer />
    </div>
  )
}

Mehr zu React 19 Features.

SEO-Implikationen

SSR SEO-Vorteile

<!-- SSR: Google sieht fertiges HTML -->
<!DOCTYPE html>
<html>
<head>
  <title>Best Pizza in Berlin | Restaurant XYZ</title>
  <meta name="description" content="Authentic Italian pizza...">
</head>
<body>
  <article>
    <h1>Best Pizza in Berlin</h1>
    <p>Our restaurant offers...</p>
  </article>
</body>
</html>

CSR SEO-Herausforderungen

<!-- CSR: Google sieht leeres HTML -->
<!DOCTYPE html>
<html>
<head>
  <title>Loading...</title>
</head>
<body>
  <div id="root"></div>
  <script src="/bundle.js"></script>
  <!-- Kein Content für Crawler -->
</body>
</html>

Workarounds für CSR + SEO:

  1. Prerendering (React Snap, Puppeteer)
  2. Dynamic Rendering (Google Bot bekommt SSR)
  3. SSG (Static Site Generation für statische Seiten)

Performance-Best Practices

SSR Optimierungen

// ✅ Streaming für schnelleren FCP
export default async function Page() {
  return (
    <div>
      <Header />  {/* Instant */}
 
      <Suspense fallback={<Skeleton />}>
        <SlowComponent />  {/* Streamt nach */}
      </Suspense>
    </div>
  )
}
 
// ✅ Caching auf Server-Level
export const revalidate = 3600 // 1 Stunde
 
// ✅ Selective Hydration
export default function MixedPage() {
  return (
    <div>
      {/* Kein JS nötig */}
      <StaticContent />
 
      {/* Nur dieser Teil wird hydrated */}
      <InteractiveWidget />
    </div>
  )
}

CSR Optimierungen

// ✅ Code-Splitting
const HeavyComponent = lazy(() => import('./HeavyComponent'))
 
// ✅ Prefetching
<link rel="prefetch" href="/api/data" />
 
// ✅ Service Worker Caching
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js')
}
 
// ✅ Skeleton Screens
function App() {
  const [data, setData] = useState(null)
 
  if (!data) return <Skeleton />
 
  return <Content data={data} />
}

Mehr in unserem Performance Guide.

Wann SSR, wann CSR?

Entscheidungsbaum

Brauchen Sie SEO?
├─ JA → Ist Content user-spezifisch?
│  ├─ NEIN → SSG (Static Site Generation)
│  └─ JA → SSR mit Caching
└─ NEIN → Viel Interaktivität?
   ├─ JA → CSR (SPA)
   └─ NEIN → SSG oder SSR

Konkrete Empfehlungen

SSR wählen wenn:

  • 🎯 SEO ist kritisch (Marketing, E-Commerce)
  • 📱 Mobile Performance wichtig (langsame Geräte)
  • ♿ Accessibility erforderlich (funktioniert ohne JS)
  • 🔗 Social Media Sharing (OG Tags, Rich Previews)

CSR wählen wenn:

  • 🔐 Behind Authentication (kein SEO nötig)
  • 💻 Desktop-heavy App (Admin Panels)
  • 🔄 Real-time Updates (Chat, Live Data)
  • 🎮 App-like Interaktion (Games, Tools)

Hybrid wählen (empfohlen):

  • 🌟 Für fast alle modernen Web-Apps
  • 💡 Next.js App Router macht es einfach
  • ⚡ Best of both worlds

Migration: CSR zu SSR

Schritt 1: Identifizieren Sie kritische Routen

// Vor: Alles CSR
const routes = [
  '/blog',           // → SSR (SEO!)
  '/products',       // → SSR (SEO!)
  '/dashboard',      // → CSR OK
  '/admin',          // → CSR OK
]

Schritt 2: Schrittweise Migration

// Phase 1: Product Pages zu SSR
// app/products/[id]/page.tsx
export default async function ProductPage({ params }) {
  const product = await getProduct(params.id)
  return <ProductView product={product} />
}
 
// Phase 2: Blog zu SSR
// app/blog/[slug]/page.tsx
export default async function BlogPost({ params }) {
  const post = await getPost(params.slug)
  return <Article post={post} />
}
 
// Phase 3: Dashboard bleibt CSR
// app/dashboard/page.tsx
'use client'
export default function Dashboard() {
  // CSR Logic
}

Tools & Frameworks

SSR Frameworks

  • Next.js - React mit SSR/SSG/ISR
  • Remix - Full-Stack React
  • SvelteKit - Svelte mit SSR
  • Nuxt - Vue.js mit SSR

CSR Frameworks

  • Create React App - Pure CSR
  • Vite + React - Schnelles CSR
  • Angular - SPA Framework

Hybrid-Optimiert

  • Next.js 15 - PPR, Server Components
  • Astro - Islands Architecture
  • Qwik - Resumability

Real-World Case Studies

Case Study 1: Blog Migration

Vor (CSR):

  • Bundle: 385 KB
  • FCP: 2.1s
  • SEO: Seite 3-5 bei Google

Nach (SSR mit Next.js):

  • Bundle: 145 KB
  • FCP: 0.6s
  • SEO: Seite 1 bei Google

Resultat: +340% organischer Traffic

Case Study 2: E-Commerce

Hybrid-Ansatz:

  • Product Pages: SSR (SEO)
  • Checkout: CSR (UX)
  • Search: CSR mit Debouncing

Metriken:

  • Conversion +18%
  • Bounce Rate -12%
  • Page Speed Score: 72 → 94

Sehen Sie unsere Portfolio-Projekte für mehr Details.

Zusammenfassung

Die Wahl zwischen SSR und CSR ist nicht binär:

SSR für SEO, Performance, Accessibility ✅ CSR für Interaktivität, Real-time, App-feeling ✅ Hybrid für moderne Web-Apps (empfohlen!)

Modern ist Hybrid:

  • Next.js App Router macht es einfach
  • Partial Prerendering kombiniert beste beider Welten
  • Server Components reduzieren Bundle-Size

Die Zukunft: Intelligente, automatische Optimierung pro Route.

Brauchen Sie Architektur-Beratung?

Als Full-Stack Agentur helfen wir bei:

  • 🏗️ Architektur-Design für Ihre Web-App
  • 🔄 Migration CSR → SSR oder umgekehrt
  • Performance-Optimierung SSR/CSR
  • 📊 SEO-Strategie für hybride Apps

Kostenlose Erstberatung

Weiterführende Ressourcen

Aktualisiert: August 2024

#SSR#CSR#Next.js#React#Architecture#Performance