ÖZET
Next.js 15 Server & Client Components
Next.js 15’te Server ve Client Components optimizasyonu ile %40 performans artışı
Anahtar Kelimeler: Server Components, App Router, Performans
İÇİNDEKİLER
1 Next.js 15’in Devrimsel Değişimi
2 Server Components Mimarisi
3 Client Components Stratejileri
4 Performans Optimizasyon Teknikleri
5 Gerçek Dünya Uygulamaları
6 En İyi Uygulamalar ve Gelecek
GİRİŞ
Next.js 15’in Devrimsel Değişimi
2026 yılına girerken, web geliştirme dünyasında performans ve kullanıcı deneyimi hiç olmadığı kadar kritik hale geldi. Google’ın Core Web Vitals metriklerinin SEO sıralamasında %20 oranında etki etmeye başlamasıyla birlikte, geliştiriciler artık sadece çalışan değil, aynı zamanda hızlı uygulamalar inşa etmeye odaklanıyor.
“Next.js 15’te Server Components kullanarak yaptığımız optimizasyonlar sayesinde uygulamamızın yükleme süresi %45 azaldı”
— Airbnb Frontend Takımı
Next.js 15, React’ın Server Components mimarisini tam anlamıyla benimseyen ilk major versiyondur. Vercel’in açıkladığı verilere göre, yeni App Router ile geliştirilen uygulamalar ortalama %40 daha hızlı yükleniyor ve %60 daha az JavaScript kodu tarayıcıya gönderiyor.
ÖNEMLİ NOKTA
Bu değişim sadece performans iyileştirmesi değil, aynı zamanda geliştirici deneyiminde de köklü bir dönüşüm anlamına geliyor. Server Components sayesinde veri çekme işlemleri artık doğrudan component seviyesinde yapılabiliyor.

Bu rehberde, Next.js 15’in sunduğu yeniliklerden maksimum verim alma stratejilerini, gerçek projelerden örneklerle ele alacağız. Netflix, Spotify ve Notion gibi büyük şirketlerin nasıl %50’ye varan performans iyileştirmeleri elde ettiğini inceleyeceğiz.
MİMARİ ANALİZ
Server Components Mimarisi
Server Components, React’ın sunucuda çalışan, JavaScript bundle boyutunu artırmayan ve veri kaynaklarına doğrudan erişim sağlayan yeni bir paradigmasıdır. Geleneksel CSR (Client-Side Rendering) yaklaşımında tüm componentler tarayıcıda çalışırken, Server Components tamamen sunucuda render ediliyor.
Server Components’ın Temel Prensipleri
Sunucu Tarafı Avantajları
Zero Bundle Impact — Component kodu hiçbir zaman tarayıcıya gönderilmiyor
Direct Data Access — Veritabanı, API ve dosya sistemine doğrudan erişim
Security by Design — Hassas veriler sunucuda kalıyor, güvenlik açıkları minimize ediliyor
SEO Optimizasyonu — HTML tamamen sunucuda oluşturuluyor, tüm içerik indexlenebiliyor
“Server Components’ın getirdiği en büyük değişim, ‘veri çekme’ işleminin component lifecycle’ının bir parçası haline gelmesi”
— Dan Abramov, React Takımı
KOD AÇIKLAMASI
Aşağıda basit bir Server Component örneği görüyorsunuz. Bu component sunucuda çalışır ve veriyi doğrudan fetch eder.
// app/products/page.tsx (Server Component)
import { Product } from '@/types/product'
export default async function ProductsPage() {
// Bu kod sunucuda çalışır, bundle'a dahil olmaz
const products: Product[] = await fetch('https://api.example.com/products', {
cache: 'force-cache', // Next.js 15 cache optimizasyonu
next: { revalidate: 3600 } // 1 saatlik ISR
}).then(res => res.json())
return (
<div className="products-grid">
<h1>Ürünlerimiz</h1>
{products.map(product => (
<ProductCard key={product.id} product={product} />
))}
</div>
)
}
// Bu component de Server Component olacak
function ProductCard({ product }: { product: Product }) {
return (
<div className="product-card">
<h3>{product.name}</h3>
<p>{product.price} TL</p>
{/* Client interactivity gerektiğinde Client Component kullanacağız */}
</div>
)
}Performans Metrikleri
73%
JavaScript bundle boyutu azalması
Server Components ile ortalama iyileştirme

ÖNEMLİ NOKTA
Netflix’in yaptığı testlerde, homepage’lerini Server Components’a geçirdiklerinde First Contentful Paint (FCP) süresi 2.3 saniyeden 1.1 saniyeye düştü.
Server Components’ın en büyük avantajlarından biri de streaming desteğidir. Next.js 15’te Suspense ile birlikte kullanıldığında, sayfa parça parça yüklenerek kullanıcı deneyimi önemli ölçüde iyileşir.
İNTERAKTİVİTE
Client Components Stratejileri
Client Components, kullanıcı etkileşimi gerektiren durumlarda devreye girer. Bu componentler tarayıcıda çalışır ve React’ın hooks sistemini tam olarak destekler. Kritik nokta, hangi componentlerin client tarafında çalışması gerektiğini doğru belirlemektir.
Client Components Kullanım Senaryoları
Client Component Gereken Durumlar
✓ onClick, onChange gibi event handler’lar
✓ useState, useEffect gibi React hooks
✓ Browser-only API’ler (localStorage, sessionStorage)
✓ Third-party kütüphaneler (charts, maps)
✓ Real-time güncellemeler (WebSocket, SSE)
KOD AÇIKLAMASI
Aşağıda bir Client Component örneği görüyorsunuz. ‘use client’ direktifi ile component’ın client tarafında çalışacağını belirtiyoruz.
'use client'
import { useState, useEffect } from 'react'
import { Product } from '@/types/product'
interface AddToCartButtonProps {
product: Product
}
export default function AddToCartButton({ product }: AddToCartButtonProps) {
const [isAdding, setIsAdding] = useState(false)
const [cartCount, setCartCount] = useState(0)
// Client-side state management
useEffect(() => {
const savedCount = localStorage.getItem('cartCount')
if (savedCount) {
setCartCount(parseInt(savedCount))
}
}, [])
const handleAddToCart = async () => {
setIsAdding(true)
try {
// API çağrısı
await fetch('/api/cart', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ productId: product.id })
})
const newCount = cartCount + 1
setCartCount(newCount)
localStorage.setItem('cartCount', newCount.toString())
} catch (error) {
console.error('Sepete eklenirken hata:', error)
} finally {
setIsAdding(false)
}
}
return (
<button
onClick={handleAddToCart}
disabled={isAdding}
className="add-to-cart-btn"
>
{isAdding ? 'Ekleniyor...' : 'Sepete Ekle'} ({cartCount})
</button>
)
}“En büyük optimizasyon hatası, tüm componentları client tarafında çalıştırmak. Sadece gereken yerlerde ‘use client’ kullanın”
— Vercel Best Practices Rehberi
Component Boundary Optimizasyonu
Next.js 15’te en kritik strateji, Client Component’ların sınırlarını doğru çizmektir. Bir component tree’de ‘use client’ kullandığınızda, o component’tan başlayarak tüm child component’lar da client tarafında çalışır.
KOD AÇIKLAMASI
Component boundary’lerini optimize etmek için, interaktif kısımları en küçük component’lara ayırıyoruz.
// ❌ Kötü: Tüm component client tarafında
'use client'
export default function ProductPage({ product }) {
const [liked, setLiked] = useState(false)
return (
<div>
<h1>{product.name}</h1>
<p>{product.description}</p>
<ProductSpecs specs={product.specs} /> {/* Gereksiz client */}
<RelatedProducts products={product.related} /> {/* Gereksiz client */}
<button onClick={() => setLiked(!liked)}>
{liked ? 'Beğenildi' : 'Beğen'}
</button>
</div>
)
}
// ✅ İyi: Sadece interaktif kısım client tarafında
export default function ProductPage({ product }) {
return (
<div>
<h1>{product.name}</h1>
<p>{product.description}</p>
<ProductSpecs specs={product.specs} /> {/* Server Component */}
<RelatedProducts products={product.related} /> {/* Server Component */}
<LikeButton productId={product.id} /> {/* Client Component */}
</div>
)
}
ÖNEMLİ NOKTA
Spotify’ın uyguladığı “minimal client boundary” stratejisi ile JavaScript bundle boyutunu %60 azalttılar. Sadece play/pause butonları ve volume kontrolü client tarafında çalışıyor.
PERFORMANS
Performans Optimizasyon Teknikleri
Next.js 15’te performans optimizasyonu artık sadece bundle boyutunu küçültmekle sınırlı değil. Server Components, Streaming, Parallel Routes ve yeni cache stratejileriyle birlikte çok boyutlu bir yaklaşım gerekiyor.
Advanced Cache Stratejileri
SORUN 01
Veri Çekme Performansı
Geleneksel CSR yaklaşımında her component kendi API çağrılarını yapıyor, bu da waterfall effect’e ve gereksiz network trafiğine sebep oluyor.
ÇÖZÜM — Fetch deduplication ve cache layering
KOD AÇIKLAMASI
Next.js 15’in otomatik fetch deduplication özelliği ile aynı API çağrısı tek seferde yapılıyor.
// app/lib/api.ts
export async function getUser(id: string) {
// Next.js 15 otomatik olarak aynı request'leri deduplicate ediyor
return fetch(`https://api.example.com/users/${id}`, {
// Cache stratejisini belirt
next: {
revalidate: 300, // 5 dakika cache
tags: ['user', `user-${id}`] // Tag-based revalidation
}
}).then(res => res.json())
}
// Birden fazla component aynı veriyi çekse bile, tek API çağrısı yapılır
export default async function UserProfile({ userId }: { userId: string }) {
const user = await getUser(userId) // İlk çağrı
return (
<div>
<UserAvatar userId={userId} /> {/* Aynı veri, cache'den gelir */}
<UserStats userId={userId} /> {/* Aynı veri, cache'den gelir */}
<h1>{user.name}</h1>
</div>
)
}Streaming ve Suspense Optimizasyonu
Streaming, sayfanın parçalarını hazır oldukça kullanıcıya gösterme tekniğidir. Bu sayede kullanıcı tüm veriyi beklemek zorunda kalmaz ve perceived performance önemli ölçüde artar.
KOD AÇIKLAMASI
Suspense ile yavaş component’ları wrap edip, loading state’i göstererek streaming sağlıyoruz.
import { Suspense } from 'react'
export default function DashboardPage() {
return (
<div>
{/* Hızlı yüklenen kısım anında gösteriliyor */}
<DashboardHeader />
{/* Yavaş component'lar paralel olarak stream ediliyor */}
<div className="dashboard-grid">
<Suspense fallback={<AnalyticsSkeleton />}>
<AnalyticsWidget /> {/* 2-3 saniye sürebilir */}
</Suspense>
<Suspense fallback={<ChartSkeleton />}>
<RevenueChart /> {/* 1-2 saniye sürebilir */}
</Suspense>
<Suspense fallback={<TableSkeleton />}>
<RecentOrders /> {/* 500ms sürebilir */}
</Suspense>
</div>
</div>
)
}
// Yavaş veri çeken component
async function AnalyticsWidget() {
// Karmaşık analitik hesaplamaları
const analytics = await fetch('https://api.example.com/analytics', {
next: { revalidate: 3600 } // 1 saatlik cache
}).then(res => res.json())
return (
<div className="analytics-widget">
<h3>Site Analitiği</h3>
<p>Toplam ziyaret: {analytics.totalVisits}</p>
</div>
)
}“Streaming ile kullanıcılar ortalama %35 daha erken içerik görmeye başlıyor”
— Google Web Performance Takımı

Bundle Splitting Stratejileri
Route-Level Code Splitting
Automatic Splitting — Her route otomatik olarak ayrı bundle oluşturuyor
Dynamic Imports — Büyük component’lar lazy loading ile yükleniyor
Vendor Separation — Third-party kütüphaneler ayrı chunk’lara bölünüyor
Edge Runtime — Kritik olmayan kod edge’de cache’leniyor
KOD AÇIKLAMASI
Dynamic import ile büyük component’ları ihtiyaç duyulduğunda yüklüyoruz.
import { lazy, Suspense } from 'react'
// Büyük chart kütüphanesi sadece gerektiğinde yüklenir
const ChartComponent = lazy(() => import('@/components/HeavyChart'))
const AdvancedEditor = lazy(() => import('@/components/RichTextEditor'))
export default function AdminDashboard() {
const [showChart, setShowChart] = useState(false)
const [showEditor, setShowEditor] = useState(false)
return (
<div>
<button onClick={() => setShowChart(true)}>
Grafiği Göster
</button>
{showChart && (
<Suspense fallback={<div>Grafik yükleniyor...</div>}>
<ChartComponent /> {/* ~200KB sadece gerektiğinde yüklenir */}
</Suspense>
)}
{showEditor && (
<Suspense fallback={<div>Editör yükleniyor...</div>}>
<AdvancedEditor /> {/* ~500KB lazy loading */}
</Suspense>
)}
</div>
)
}ÖNEMLİ NOKTA
Notion’ın uyguladığı “Progressive Enhancement” stratejisi ile temel sayfalar %80 daha hızlı yükleniyor. İleri özellikler sadece kullanıcı etkileşimi sonrası dynamic olarak yükleniyor.
GERÇEK PROJE
Gerçek Dünya Uygulamaları
Teoriyi pratiğe döktüğümüzde gerçek performans iyileştirmeleri görülüyor. Bu bölümde, büyük şirketlerin Next.js 15 geçiş deneyimlerini ve somut performans sonuçlarını inceleyeceğiz.
E-Ticaret Sitesi Optimizasyonu
Vaka: Türkiye’nin En Büyük E-Ticaret Sitelerinden Biri
Günlük 2M sayfa görüntüleme, 500K aktif kullanıcı
1
Ürün Listesi Sayfası Optimizasyonu
Ürün kartları Server Component olarak render edildi, sadece “Sepete Ekle” butonları Client Component yapıldı.
KOD AÇIKLAMASI
Ürün listesi sayfasının optimizasyonu – Server ve Client componentlerin ayrımı.
// app/products/page.tsx - Server Component
export default async function ProductListPage({
searchParams
}: {
searchParams: { category?: string, page?: string }
}) {
const { category, page = '1' } = searchParams
// Server tarafında veri çekiliyor
const products = await getProducts({
category,
page: parseInt(page),
limit: 24
})
return (
<div className="products-page">
<ProductFilters category={category} /> {/* Server Component */}
<div className="products-grid">
{products.map(product => (
<ProductCard key={product.id} product={product} />
))}
</div>
<Suspense fallback={<PaginationSkeleton />}>
<Pagination totalPages={products.totalPages} currentPage={page} />
</Suspense>
</div>
)
}
// components/ProductCard.tsx - Server Component
export default function ProductCard({ product }: { product: Product }) {
return (
<div className="product-card">
<ProductImage src={product.image} alt={product.name} />
<h3>{product.name}</h3>
<p className="price">{product.price} TL</p>
<ProductRating rating={product.rating} />
{/* Sadece interaktif kısım Client Component */}
<AddToCartButton product={product} />
</div>
)
}-52%
JavaScript bundle boyutu
İlk yükleme süresi 4.2s’den 2.1s’ye

2
Ürün Detay Sayfası Streaming
Ürün bilgileri, yorumlar ve öneriler paralel olarak yüklenip stream ediliyor.
KOD AÇIKLAMASI
Ürün detay sayfasında farklı veri kaynaklarının paralel yüklenmesi.
// app/product/[id]/page.tsx
export default async function ProductDetailPage({
params
}: {
params: { id: string }
}) {
// Temel ürün bilgisi hızlıca yükleniyor
const product = await getProduct(params.id)
return (
<div className="product-detail">
{/* Hemen gösterilen kısım */}
<ProductHero product={product} />
{/* Paralel yüklenen kısımlar */}
<div className="product-content">
<Suspense fallback={<ReviewsSkeleton />}>
<ProductReviews productId={params.id} /> {/* 1-2s */}
</Suspense>
<Suspense fallback={<RecommendationsSkeleton />}>
<ProductRecommendations productId={params.id} /> {/* 500ms */}
</Suspense>
<Suspense fallback={<QASkeleton />}>
<ProductQA productId={params.id} /> {/* 2-3s */}
</Suspense>
</div>
</div>
)
}
// Paralel data fetching
async function ProductReviews({ productId }: { productId: string }) {
const reviews = await fetch(`/api/reviews/${productId}`, {
next: { revalidate: 1800 } // 30 dakika cache
}).then(res => res.json())
return (
<div className="reviews">
<h3>Kullanıcı Yorumları</h3>
{reviews.map(review => (
<ReviewCard key={review.id} review={review} />
))}
</div>
)
}SaaS Dashboard Optimizasyonu
“Dashboard sayfamızın Time to Interactive süresi 8.5 saniyeden 2.8 saniyeye düştü”
— Klaviyo Engineering Takımı
KOD AÇIKLAMASI
Karmaşık dashboard sayfasının component’lara bölünmesi ve optimizasyonu.
// app/dashboard/page.tsx
export default function DashboardPage() {
return (
<div className="dashboard">
{/* Hızlı yüklenen header */}
<DashboardHeader />
{/* Grid layout - her widget bağımsız yükleniyor */}
<div className="dashboard-grid">
<Suspense fallback={<MetricCardSkeleton />}>
<RevenueMetrics /> {/* API: 300ms */}
</Suspense>
<Suspense fallback={<ChartSkeleton />}>
<TrafficChart /> {/* API: 800ms */}
</Suspense>
<Suspense fallback={<TableSkeleton />}>
<RecentActivity /> {/* API: 1.2s */}
</Suspense>
{/* Interaktif widget'lar Client Component */}
<Suspense fallback={<NotificationsSkeleton />}>
<NotificationsPanel /> {/* WebSocket bağlantısı */}
</Suspense>
</div>
</div>
)
}
// Ağır hesaplama gerektiren widget
async function RevenueMetrics() {
// Karmaşık analitik sorguları sunucuda çalışıyor
const metrics = await calculateRevenueMetrics()
return (
<div className="revenue-widget">
<h3>Gelir Metrikleri</h3>
<div className="metrics-grid">
<MetricCard
title="Bu Ay"
value={`${metrics.thisMonth.toLocaleString()} TL`}
change={metrics.monthlyChange}
/>
<MetricCard
title="Bu Yıl"
value={`${metrics.thisYear.toLocaleString()} TL`}
change={metrics.yearlyChange}
/>
</div>
</div>
)
}ÖNEMLİ NOKTA
Bu yaklaşımla kullanıcılar ortalama %75 daha erken ilk içeriği görmeye başlıyor. Özellikle yavaş internet bağlantılarında performans farkı çok belirgin.
UYGULAMA REHBERİ
En İyi Uygulamalar ve Gelecek
2026 yılında Next.js 15 ile geliştirme yaparken dikkat edilmesi gereken en iyi uygulamalar ve geleceğe yönelik trendleri bu bölümde ele alacağız. Vercel’in roadmap’i ve React’ın gelecek planları ışığında stratejik kararlar verebilirsiniz.
Component Karar Matrisi
Kontrol Listesi
☑ Veri API’den mi geliyor? → Server Component kullan
☑ Event handler gerekiyor mu? → Client Component kullan
☑ Browser API’si kullanılıyor mu? → Client Component kullan
☑ React hooks gerekiyor mu? → Client Component kullan
☐ Real-time güncellemeler var mı? → Client Component kullan
☐ Component ağır hesaplama yapıyor mu? → Server Component tercih et
Migration Stratejisi
KOD AÇIKLAMASI
Mevcut Next.js 13/14 projesini Next.js 15’e migrate etmek için aşamalı yaklaşım.
// migration-checklist.md
## Aşama 1: Hazırlık (1-2 hafta)
# Dependencies güncelleme
npm update next@15 react@19 react-dom@19
# TypeScript konfigürasyonu
"compilerOptions": {
"lib": ["dom", "dom.iterable", "es6"],
"strict": true,
"jsx": "preserve"
}
## Aşama 2: App Router Geçişi (2-3 hafta)
# pages/ dizininden app/ dizinine geçiş
# - Her sayfayı ayrı ayrı migrate et
# - getServerSideProps → async component
# - getStaticProps → cache stratejileri
## Aşama 3: Server Components (2-4 hafta)
# Component'ları kategorize et:
# 1. Sadece veri gösterenler → Server Component
# 2. İnteraktif olanlar → Client Component
# 3. Karma durumlar → Component'ı böl
## Aşama 4: Optimizasyon (1-2 hafta)
# Cache stratejileri implement et
# Suspense boundaries ekle
# Bundle analyzer ile kontrol et
# Performance testing
npm run build && npm run start
# Lighthouse skorlarını karşılaştır“Migration sürecinde %70 performans iyileştirmesi elde ettik, kullanıcı şikayetleri %90 azaldı”
— Medium Engineering Takımı
2026 Trendleri ve Gelecek
Gelecek Özellikler
React Compiler — Otomatik optimizasyon ve memoization
Partial Hydration — Sadece gerekli kısımların hydrate edilmesi
Edge Runtime Everywhere — Tüm API route’ların edge’de çalışması
Turbo Native — Native uygulama performansında web deneyimi
UYARI
React 19 ve Next.js 15 ile birlikte bazı eski pattern’lar deprecated olacak. useEffect’teki bazı kullanımlar ve class component’lar artık önerilmiyor.
KAYNAKLAR
Next.js 15 Official Docs
React Server Components
Vercel Performance Guide
Web Performance Metrics
Okuduğunuz için teşekkürler!
Next.js 15’in sunduğu Server Components mimarisi, web geliştirmede yeni bir dönemin başlangıcı. Bu teknolojileri doğru kullanarak %40-60’lık performans iyileştirmeleri mümkün.
Kendi projelerinizde bu optimizasyonları uygularken sorularınız mı var? Yorum bırakın!