Next.js SSR performans optimizasyonu React web performansı

Next.js ile SSR Performans Optimizasyonu Rehberi

Abdullah Bozdağ 17 Mart 2026
Next.js ile SSR Performans Optimizasyonu Rehberi

Next.js'de SSR Neden Yavaşlar?

Server-Side Rendering (SSR), kullanıcıya ilk anlamlı içeriği hızlı sunmak için güçlü bir yöntem. Ama yanlış yapılandırıldığında tam tersi etki yaratır: sunucu yanıt süreleri uzar, TTFB (Time to First Byte) artar ve kullanıcı deneyimi bozulur.

Sorunun kaynağı genellikle üç yerde gizlidir: gereksiz veri çekme işlemleri, eksik cache stratejileri ve büyük JavaScript bundle'ları. Bu yazıda Next.js SSR performansını somut tekniklerle nasıl iyileştireceğinizi anlatıyoruz.

1. Veri Çekme Katmanını Optimize Edin

SSR'da en büyük darboğaz veri çekme aşamasıdır. Sayfa render edilmeden önce sunucunun tüm veriyi hazırlaması gerekir. Bu süre uzadıkça TTFB doğrudan artar.

Paralel Veri Çekme

Birden fazla API çağrısı yapıyorsanız bunları sıralı değil paralel çalıştırın. Promise.all bu işin en temel aracıdır.

// Yavaş: Sıralı çağrılar
const user = await getUser(id);
const posts = await getPosts(id);
const stats = await getStats(id);

// Hızlı: Paralel çağrılar
const [user, posts, stats] = await Promise.all([
getUser(id),
getPosts(id),
getStats(id),
]);

Bu basit değişiklik, üç ayrı 200ms'lik çağrıyı 600ms yerine 200ms'e düşürür.

Gereksiz Veriyi Çekmeyin

API'den dönen verinin tamamını kullanmıyorsanız, GraphQL veya API tarafında field filtering uygulayın. Büyük JSON payload'ları hem ağ hem de parse süresini artırır.

2. Cache Stratejilerini Doğru Kurun

Next.js App Router ile birlikte gelen fetch API'si yerleşik cache desteği sunar. Bunu doğru kullanmak SSR performansında en büyük farkı yaratır.

fetch Cache Seçenekleri

// Varsayılan: Her istekte yeniden çeker (no-store)
fetch('https://api.example.com/data', {
cache: 'no-store'
});

// Cache'le ve belirli süre tut
fetch('https://api.example.com/data', {
next: { revalidate: 60 } // 60 saniyede bir yenile
});

// Statik cache: Build zamanında çek, değişmez
fetch('https://api.example.com/data', {
cache: 'force-cache'
});

Her sayfanın ihtiyacına göre farklı strateji uygulayın. Sık değişmeyen veriler için revalidate değerini yüksek tutun. Kullanıcıya özel veriler için cache'i devre dışı bırakın.

Route Segment Config

Sayfa düzeyinde cache davranışını kontrol etmek için route segment config kullanabilirsiniz:

// app/products/page.tsx
export const revalidate = 3600; // 1 saat
export const dynamic = 'force-static'; // Statik olarak oluştur

3. Streaming SSR ile TTFB'yi Düşürün

Klasik SSR'da sunucu tüm veriyi çeker, tüm HTML'i oluşturur ve tek seferde gönderir. Streaming SSR ise hazır olan kısımları anında göndermeye başlar.

Next.js App Router'da bu özellik loading.tsx ve React Suspense ile çalışır:

// app/dashboard/page.tsx
import { Suspense } from 'react';
import { UserStats } from './UserStats';
import { RecentOrders } from './RecentOrders';

export default function Dashboard() {
return (
<div>
<h1>Dashboard</h1>
<Suspense fallback={<p>İstatistikler yükleniyor...</p>}>
<UserStats />
</Suspense>
<Suspense fallback={<p>Siparişler yükleniyor...</p>}>
<RecentOrders />
</Suspense>
</div>
);
}

Bu yapıda sayfa iskeleti hemen gönderilir. UserStats ve RecentOrders bileşenleri hazır oldukça stream edilir. Kullanıcı boş bir ekran yerine anında içerik görür.

4. Bundle Boyutunu Kontrol Altında Tutun

SSR'dan dönen HTML hızlı yüklense bile, büyük JavaScript bundle'ları hydration süresini uzatır. Bu da sayfanın etkileşime geçme süresini (TTI) doğrudan etkiler.

Dynamic Import Kullanın

Sayfa yüklenirken gerekmeyen bileşenleri dinamik olarak yükleyin:

import dynamic from 'next/dynamic';

const HeavyChart = dynamic(() => import('./HeavyChart'), {
ssr: false, // Sunucuda render etme
loading: () => <p>Grafik yükleniyor...</p>
});

ssr: false seçeneği, bileşenin sadece istemcide yüklenmesini sağlar. Sunucu tarafında gereksiz iş yapılmasını engeller.

Bundle Analyzer ile Kontrol Edin

@next/bundle-analyzer paketini kurarak hangi modüllerin ne kadar yer kapladığını görselleştirin. Büyük kütüphaneleri (moment.js, lodash gibi) daha hafif alternatiflerle değiştirin.

// next.config.js
const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
});

module.exports = withBundleAnalyzer({
// diğer config
});

5. Sunucu Bileşenleri ve İstemci Bileşenlerini Ayırın

Next.js App Router'da bileşenler varsayılan olarak Server Component'tir. Bu büyük bir avantaj: sunucu bileşenleri istemciye JavaScript göndermez.

Ama her yere 'use client' eklerseniz bu avantajı kaybedersiniz. Şu kuralı uygulayın:

  1. Sunucu bileşeni: Veri çekme, veritabanı sorguları, statik içerik gösterimi
  2. İstemci bileşeni: Event handler'lar, state yönetimi, tarayıcı API'leri

İstemci bileşenlerini mümkün olduğunca küçük tutun ve ağacın yaprak düğümlerine itin. Üst düzey layout'lar ve sayfa bileşenleri sunucu bileşeni olarak kalmalıdır.

Performansı Ölçün, Tahmin Etmeyin

Optimizasyon yapmadan önce ve sonra metrikleri ölçün. Next.js'in yerleşik next/web-vitals desteğini kullanarak Core Web Vitals verilerini toplayabilirsiniz. Özellikle şu metriklere odaklanın:

  1. TTFB: Sunucu yanıt süresi. Cache ve veri çekme optimizasyonlarıyla düşer.
  2. LCP: En büyük içerik elemanının render süresi. Streaming SSR ile iyileşir.
  3. TTI: Etkileşime hazır olma süresi. Bundle boyutu küçüldükçe düşer.
Ölçemediğiniz şeyi optimize edemezsiniz. Lighthouse, WebPageTest ve gerçek kullanıcı verilerini (RUM) birlikte kullanın.

Özet

Next.js SSR performans optimizasyonu tek bir ayarla çözülen bir konu değil. Veri çekme, cache, streaming, bundle yönetimi ve bileşen mimarisi birlikte çalışmalı. İşe en büyük darboğazı bulmakla başlayın, ölçün ve adım adım iyileştirin.

Paylas:

Abdullah Bozdağ

Abdullah Bozdağ

RadKod Ekibi

Ilgili Yazilar