Blog

Next.js'te Rendering

Kırmızı dev 'nextjs' yazısının önünde, güneş gözlüklü bir sphynx kedi, bir pençesi kapalı bir dizüstü bilgisayarın üzerinde oturuyor

Tarayıcının eline gelen HTML'i birisi üretti. Soru şu: ne zaman üretti?

Cevap kabaca şu dördünden biri. Build ederken. Kullanıcı isterken. Daha önce üretilmişti, arka planda tazelendi. Ya da hiç üretilmedi, tarayıcı kendisi çizdi.

Modern Next.js'te bu bir "strateji seçme" meselesinden çok, her parça içeriğe "bu ne zaman üretilmeli?" diye sormaya dönüşüyor. Aşağıda beş yaklaşımı sırayla açıyorum.

CSR (Client-Side Rendering)

App Router'da "use client" yazmak bir component'i doğrudan CSR yapmaz. Component yine ilk request'te server'da render edilip HTML'e dahil olabilir. Server render'ını gerçekten kapatıp render'ı client'a taşımak istiyorsan ssr: false ile dinamik import kullanırsın.

CSR; window / document kullanan, browser'a özel çalışan veya SEO'nun önemli olmadığı interaktif ekranlarda mantıklı. Ama SEO ve hızlı ilk render önemliyse her şeyi CSR'a bırakmak genelde iyi bir tercih değil: tarayıcı önce boş bir kabuk alır, JS'i indirip çalıştırır, veriyi ayrı bir istekle çeker ve içerik ancak ondan sonra çizilir.

CSR beş adımda: sayfayı istiyorsunuz, boş bir HTML kabuğu geliyor, tarayıcı JavaScript'i indirip çalıştırıyor, JavaScript veriyi istiyor ve içerik ancak ondan sonra çiziliyor

SSG (Static Site Generation)

Sayfa build time'da generate edilir. Veri build sırasında fetch edilir ve elde edilen HTML statik olarak oluşturulup CDN'e deploy edilir. Kullanıcı request attığında server tarafında tekrar data fetch edilmez; CDN hazır HTML'i direkt döner.

Bu yüzden TTFB (Time to First Byte) request anındaki data fetch süresinden etkilenmez.

Dezavantajı, içerik güncellendiğinde yeniden build/deploy gerekmesi ve çok büyük dataset'lerde build süresinin ciddi şekilde uzayabilmesidir.

SSG: build time'da veri çekiliyor, HTML üretilip CDN'e kopyalanıyor, hepsi kullanıcı gelmeden önce; siz sayfayı istediğinizde CDN hazır dosyayı döndürüyor

ISR (Incremental Static Regeneration)

ISR, statik sayfaların belirli koşullarda yeniden generate edilmesini sağlayarak SSG ile SSR arasında bir yaklaşım sunar. Sayfa build time'da generate edilir ve revalidate ile cache süresi belirlenir.

revalidate: 60, her 60 saniyede bir yenile demek değildir. Süre dolduktan sonra gelen ilk request mevcut HTML'i alır ve arka planda yeni sayfa generate edilir. Sonraki request yeni içeriği alır.

Yani ISR request-driven regeneration kullanır; trafik yoksa regeneration da yoktur.

revalidateTag ile süreyi beklemeden cache invalidation tetiklenebilir.

Dezavantajı: stok, canlı fiyat veya kalan koltuk gibi anlık doğruluk gerektiren verilerde bir kullanıcının stale data görmesi kabul edilemez.

ISR: HTML bir son kullanma süresiyle build ediliyor, kullanıcı A süre dolmadan gelip sayfayı alıyor, kullanıcı B süre dolduktan sonra gelip yine eski sayfayı alırken isteği arka planda bir rebuild tetikliyor ve kullanıcı C yeni üretilmiş sayfayı alıyor

SSR (Server-Side Rendering)

Kullanıcı sayfayı istediğinde Next.js gerekli verileri server'da fetch eder, HTML'i üretir ve response olarak gönderir.

Next.js App Router'da SSR özellikle request'e bağlı veya güncel olması gereken veriler için önemlidir. cookies(), headers(), searchParams veya cache'lenmemiş data fetch gibi dinamik API'ler kullanıldığında route dynamic render edilir.

Bunun karşılığında her request'te server-side işlem yapıldığı için TTFB, data source'un latency'sinden etkilenir. Yani SSR güncel ve kişiselleştirilmiş içerik sağlar ama bunun maliyeti request başına server-side rendering'dir.

SSR: her request'te sayfayı istiyorsunuz, server veriyi çekiyor, server HTML'i üretiyor ve içerik çiziliyor; döngü her istek için baştan işliyor

PPR (Partial Prerendering)

PPR, sayfanın statik ve dinamik bölümlerini aynı response içinde birleştiren bir rendering yaklaşımıdır.

Build sırasında statik kabuk hazırlanır, dinamik bölümler için placeholder bırakılır. Kullanıcı request attığında kabuk hemen gönderilir; dinamik parçalar server'da hazırlandıkça aynı response içinde doldurulur.

Önceki stratejilerde sayfa genel olarak statik ya da dinamik kabul ediliyordu. PPR ile sayfanın sadece gerçekten dinamik olan kısmını request time'da render edebilirsin.

Next.js 16'da cacheComponents: true ile model daha da değişiyor: cache'lenecek içerikleri use cache ile açıkça işaretliyorsun.

Dikkat: dinamik içerik bir Suspense sınırıyla ayrılmazsa tüm shell'i bloke edebilir. Ayrıca fallback tasarımı önemlidir; kullanıcı önce fallback'i, ardından gerçek içeriği görür.

PPR: dinamik slot'ları boş bırakılmış statik bir kabuk önceden build ediliyor; siz sayfayı istediğinizde kabuk anında geliyor, server dinamik parçaları hazırlıyor ve slot'lar aynı response içinde doluyor

TL;DR

Pratikte artık sorulacak soru "hangi rendering stratejisini kullanmalıyım?" değil. Önce içeriğin kendisine bakmak gerekiyor:

  • Bu içerik kullanıcıya özel mi?
  • Ne sıklıkla değişiyor ve birinin eski hâlini görmesi kabul edilebilir mi?
  • Daha da önemlisi, bu dinamik parçanın sayfanın geri kalanını bekletmesine gerçekten gerek var mı?

Bu soruların cevapları; içeriğin build time'da mı hazırlanacağını, cache'lenip ne zaman yenileneceğini veya her request'te mi render edileceğini belirliyor. Modern Next.js rendering yaklaşımında amaç tek bir strateji seçmek değil, her içeriği ihtiyacına göre doğru zamanda render etmek.