Web performansı; kullanıcıların içeriğe erişme süresini, etkileşim akıcılığını ve görsel kararlılığı etkiler. Google, Core Web Vitals'ı sıralama sistemlerinde kullanılan sayfa deneyimi sinyalleri arasında sayar; ancak iyi bir sayfa deneyiminin üst sıraları garanti etmediğini açıkça belirtir. Hız ile dönüşüm arasındaki etki de ürün, kitle, cihaz ve ölçüm yöntemine göre değişir; bu nedenle evrensel kayıp yüzdeleri yerine alan verisi kullanılmalıdır.
Core Web Vitals
Core Web Vitals eşikleri, sayfa yüklemelerinin 75. yüzdelik diliminde ve mobil ile masaüstü ayrı değerlendirilerek uygulanır. “İyi” aralıklar hedef niteliğindedir; tek bir laboratuvar koşusu gerçek kullanıcı dağılımının yerini tutmaz.
LCP (Largest Contentful Paint)
Sayfanın en büyük içerik elementinin render süresi.
- İyi: ≤ 2.5 saniye
- İyileştirmeli: > 2.5 ve ≤ 4 saniye
- Kötü: > 4 saniye
INP (Interaction to Next Paint)
Kullanıcı etkileşimlerinin yanıt süresi (FID'nin yerini aldı).
- İyi: ≤ 200 ms
- İyileştirmeli: > 200 ve ≤ 500 ms
- Kötü: > 500 ms
CLS (Cumulative Layout Shift)
Sayfa yüklenirken içeriğin beklenmedik şekilde kayma miktarı.
- İyi: ≤ 0.1
- İyileştirmeli: > 0.1 ve ≤ 0.25
- Kötü: > 0.25
1. Görsel Optimizasyon
Görseller bazı sayfalarda aktarım boyutunun ve LCP süresinin önemli bölümünü oluşturabilir; bazı sayfalarda ise asıl darboğaz JavaScript, font, sunucu yanıtı veya üçüncü taraf kodudur. Öncelik, ağ waterfall'u ve LCP alt parçaları ölçülerek belirlenmelidir.
Modern Format Kullanımı
<!-- picture elementi ile format fallback -->
<picture>
<source srcset="/hero.avif" type="image/avif" />
<source srcset="/hero.webp" type="image/webp" />
<img src="/hero.jpg" alt="Hero görsel" width="1200" height="630" />
</picture>
WebP veya AVIF, belirli görsellerde JPEG/PNG'den daha küçük çıktı verebilir; sonuç kaynak görsele, encoder'a, kalite ayarına ve içerik türüne bağlıdır. Aynı görsel için hedef viewport'larda çıktı boyutu ve görsel kalite karşılaştırılmalı, gereken tarayıcılar için fallback bırakılmalıdır. Yukarıdaki picture örneği bu seçim sırasını gösterir; sabit bir tasarruf oranı vaat etmez.
Next.js Image Optimization
import Image from "next/image";
// next/image responsive srcset üretir ve görüntüyü boyutlandırır.
// Çıktı formatı next.config ayarına ve tarayıcının Accept başlığına bağlıdır.
function HeroSection() {
return (
<Image
src="/hero.jpg"
alt="Dijital proje ekranı"
width={1200}
height={630}
preload // LCP adayı olduğu ölçümle doğrulandıysa
placeholder="blur"
blurDataURL="data:image/jpeg;base64,/9j/4AAQ..."
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 80vw, 1200px"
/>
);
}
Next.js 16'da eski priority prop'u yerine preload kullanılması önerilir. placeholder="blur" da her uzak görsel için otomatik değildir; gerektiğinde güvenilir bir blurDataURL sağlanmalıdır. Güncel prop ve format davranışı Next.js Image dokümanında açıklanır.
Görsel Bütçesi Belirleme
- Her görselin gerçek görüntülenme boyutuna uygun
srcsetvesizesdeğerlerini doğrulayın. - En/boy oranını ayırarak CLS riskini azaltın.
- Fotoğraf, şeffaf grafik ve basit ikon için formatı içerik türüne göre seçin; SVG her görsel için uygun değildir.
- Dosya bütçesini sabit evrensel bir KB sınırı olarak değil, hedef cihaz ve ağ koşullarındaki LCP bütçesinden türetin.
- Kalite kararını yalnızca dosya boyutuyla değil, görsel karşılaştırma ve kullanıcı bağlamıyla verin.
2. Lazy Loading
Görseller için Lazy Loading
<!-- Native lazy loading — modern tarayıcılarda yerleşik -->
<img src="product.jpg" alt="Ürün" loading="lazy" width="400" height="300" />
LCP görselini lazy-load etmek keşif ve indirme başlangıcını geciktirebilir. web.dev LCP rehberi, LCP kaynağının HTML'den keşfedilebilir olmasını ve lazy loading uygulanmamasını önerir. Next.js'te preload yalnızca gerçekten kritik kaynak için kullanılmalı; gereksiz preload ağ önceliği rekabeti yaratabilir.
Component Lazy Loading
"use client";
import dynamic from "next/dynamic";
// Ağır component'leri lazy load edin
const HeavyChart = dynamic(() => import("./HeavyChart"), {
loading: () => <div className="h-96 animate-pulse bg-gray-100 rounded" />,
ssr: false, // Sadece istemcide yükle
});
const VideoPlayer = dynamic(() => import("./VideoPlayer"), {
loading: () => <div className="aspect-video bg-gray-900 rounded" />,
});
// Kullanım
function Dashboard() {
return (
<div>
<h1>Dashboard</h1>
<HeavyChart data={chartData} />
<VideoPlayer url={videoUrl} />
</div>
);
}
Intersection Observer ile Lazy Loading
"use client";
import type { ReactNode } from "react";
import { useRef, useEffect, useState } from "react";
function LazySection({ children }: { children: ReactNode }) {
const ref = useRef<HTMLDivElement>(null);
const [isVisible, setIsVisible] = useState(false);
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setIsVisible(true);
observer.disconnect();
}
},
{ rootMargin: "200px" } // 200px önceden yükle
);
if (ref.current) observer.observe(ref.current);
return () => observer.disconnect();
}, []);
return (
<div ref={ref}>
{isVisible ? children : <div className="h-96" />}
</div>
);
}
ssr: false, bir performans varsayılanı değildir; yalnızca tarayıcı API'sine bağımlı client bileşenlerinde değerlendirilmelidir. Kritik içeriği tamamen client render'a taşımak ilk görüntüleme ve erişilebilirlik davranışını olumsuz etkileyebilir. Intersection Observer örneğindeki 200 piksel eşik de hipotetiktir; kaydırma hızı, ağ ve bileşen maliyetiyle test edilmelidir.
3. Code Splitting
Route-Based Splitting (Otomatik)
Next.js build sistemi rota segmentleri ve paylaşılan bağımlılıklar için code splitting uygular. Ancak hangi ortak chunk'ların indirileceği import grafiğine ve framework sürümüne bağlıdır; “bir rota diğer rotanın hiçbir kodunu indirmez” varsayımı bundle analiziyle doğrulanmalıdır. Component seviyesindeki dinamik import davranışı Next.js lazy loading rehberinde açıklanır.
Component-Based Splitting
// Koşullu yükleme — sadece gerektiğinde
import dynamic from "next/dynamic";
const AdminPanel = dynamic(() => import("./AdminPanel"));
const ChatWidget = dynamic(() => import("./ChatWidget"));
const CookieBanner = dynamic(() => import("./CookieBanner"));
type User = { isAdmin: boolean };
function App({
user,
showChat,
}: {
user?: User;
showChat: boolean;
}) {
return (
<main>
<Header />
<Content />
{user?.isAdmin && <AdminPanel />}
{showChat && <ChatWidget />}
<CookieBanner />
</main>
);
}
Bundle Analizi
npm install --save-dev @next/bundle-analyzer
// next.config.ts
import type { NextConfig } from "next";
import bundleAnalyzer from "@next/bundle-analyzer";
const withBundleAnalyzer = bundleAnalyzer({
enabled: process.env.ANALYZE === "true",
});
const nextConfig: NextConfig = {};
export default withBundleAnalyzer(nextConfig);
# POSIX shell
ANALYZE=true npm run build
Bundle analyzer çıktısı; paket sürümüne, import biçimine, minifier'a ve hedef tarayıcılara göre değişir. Sabit paket boyutları yerine şu kararları kendi üretim build'inizde ölçün:
- Tarih işlemleri için önce platformdaki
IntlAPI'lerinin ihtiyacı karşılayıp karşılamadığını kontrol edin; kütüphane değişimini yalnızca boyuta göre yapmayın. - Yardımcı fonksiyon paketlerinde kullanılan export'ların tree-shake edilip edilmediğini build çıktısında doğrulayın.
- Grafik, editör veya harita gibi büyük client bileşenlerini yalnızca ihtiyaç duyulan rotada ya da etkileşimden önce yüklemeyi değerlendirin.
- Paketi değiştirdikten sonra işlev, erişilebilirlik, locale ve lisans gereksinimlerini yeniden test edin.
4. Font Optimizasyonu
// Next.js font optimizasyonu — otomatik self-hosting
import type { ReactNode } from "react";
import { Inter, Poppins } from "next/font/google";
const inter = Inter({
subsets: ["latin", "latin-ext"],
display: "swap", // Font yüklenirken metni görünür tutar
variable: "--font-inter",
});
const poppins = Poppins({
weight: ["400", "600", "700"],
subsets: ["latin", "latin-ext"],
display: "swap",
variable: "--font-poppins",
});
// Layout'ta kullan
export default function RootLayout({ children }: { children: ReactNode }) {
return (
<html className={`${inter.variable} ${poppins.variable}`}>
<body>{children}</body>
</html>
);
}
Font optimizasyon kuralları:
- Kullanılmayan varyantları yüklemeyin: Her aile, ağırlık ve stil ek ağ/işleme maliyeti oluşturabilir.
- Karakter kapsamını doğrulayın: Seçilen subset'in içerikteki Türkçe ve diğer gerekli karakterleri kapsadığını test edin.
- Fallback metriğini kontrol edin:
display: swapmetni erken gösterebilir; fallback ile web fontu arasındaki metrik farkı CLS oluşturabilir. - Teslimatı ölçün:
next/font, font dosyalarını build sırasında indirip uygulamayla birlikte sunabilir; build ortamının ağa erişimi ve font lisansı ayrıca kontrol edilmelidir.
5. CDN ve Caching Stratejileri
HTTP Cache Headers
Dosya uzantısına göre bütün yanıtlara geniş kapsamlı cache başlığı ekleyen bir proxy/middleware kuralı güvenli değildir. Aynı uzantı altında sürümlenmeyen dosya bulunabilir; HTML ise oturum veya kişiselleştirilmiş veri içerebilir. Next.js'in hash'li build asset'leri için framework'ün ürettiği başlıkları koruyun ve güncel Cache Components rehberini kullandığınız render modeliyle birlikte kontrol edin. Cache Components kapalıysa aynı sayfadaki önceki model bağlantısını izleyin.
Aşağıdaki politika bir kopyala-yapıştır ayarı değil, karar modelidir:
Cache stratejisi özeti
| İçerik Türü | Değerlendirilebilecek politika | Kontrol |
|---|---|---|
| Hash'li build asset'leri | Uzun süreli public ve immutable cache | URL içerik değişince değişiyor mu? |
| Sürümlenmiş public görsel/font | Uzun süreli public cache | Dosya adı sürümlü mü, silme planı var mı? |
| Herkese açık HTML | Framework revalidation veya kısa paylaşımlı cache | İçerik ne kadar eski kalabilir? |
| Oturumlu/kişiselleştirilmiş HTML | Shared cache'i kapatma veya doğru private politika | Cache anahtarı kullanıcı verisini ayırıyor mu? |
| API yanıtları | Endpoint ve veri sınıfına özel | Yetki, güncellik ve invalidation nasıl çalışıyor? |
CDN panelinde “cache hit” görmek doğruluk kanıtı değildir. Deploy sonrası başlıklar, invalidation, oturum ayrımı ve stale içerik davranışı gerçek yanıtlar üzerinden test edilmelidir.
6. JavaScript Optimizasyonu
Third-Party Script Yönetimi
Next.js Script dokümanı, yükleme zamanını ihtiyaca göre ayıran stratejileri açıklar:
| Strateji | Değerlendirilebilecek kullanım | Risk |
|---|---|---|
beforeInteractive |
Sayfa etkileşiminden önce gerekli, site genelindeki nadir scriptler | Kritik ağ/işleme yolunu uzatabilir |
afterInteractive |
Hydration başladıktan sonra gereken scriptler | Ana thread ve INP maliyeti yaratabilir |
lazyOnload |
Düşük öncelikli widget veya yardımcı script | Özellik geç hazır olabilir |
Üçüncü taraf kodu yalnızca daha geç yüklemek toplam CPU, ağ veya gizlilik maliyetini kaldırmaz. İş gereksinimi olmayan scriptleri çıkarın; kalanları kullanıcı izni, hata davranışı, Content Security Policy ve gerçek cihaz profiliyle test edin.
7. Ölçüm Araçları
Geliştirme Aşamasında
- Chrome DevTools Lighthouse: Yerel performans testi
- Chrome DevTools Performance paneli: CPU profiling, long tasks tespit
- Chrome DevTools Network paneli: Waterfall analizi, büyük dosya tespiti
Production'da
- Google PageSpeed Insights: Lighthouse laboratuvar verisi; yeterli CrUX kapsamı varsa alan verisi
- Chrome UX Report (CrUX): Gerçek kullanıcı metrikleri
- Google Search Console — Core Web Vitals raporu: Sayfa gruplarının performansı
Kontrol Listesi
Bu liste başlangıç çerçevesidir; uygulama sırası ölçülen kullanıcı etkisine ve geliştirme maliyetine göre değişmelidir:
- Mevcut durumu ölçün (Lighthouse + CrUX)
- Alan verisini rota, cihaz, bağlantı ve sürüm kırılımlarında inceleyin
- LCP, INP ve CLS'nin en büyük alt nedenlerini belirleyin
- Görsel ve font teslimatını ölçülen ihtiyaca göre düzenleyin
- Ana thread'i bloke eden uygulama ve üçüncü taraf JavaScript'ini azaltın
- Gerekli rotalarda code splitting uygulayın ve tekrar ölçün
- Cache ve CDN politikasını içerik güncelliği ile yetkilendirme kurallarına göre kurun
- Erişilebilirlik ve işlev regresyonlarını test edin
- Tekrar ölçün ve karşılaştırın
- Sürüm bazlı gerçek kullanıcı izleme kurun
Sonuç
Web performansı tek seferlik bir skor çalışması değildir. Alan verisi, laboratuvar profili ve uygulama telemetrisi birlikte kullanıldığında ekip hangi darboğazın hangi kullanıcı grubunu etkilediğini görebilir. Framework ve CDN varsayılanları bazı teslimat işlerini kolaylaştırsa da doğru görsel önceliğini, JavaScript kapsamını, veri cache'ini veya üçüncü taraf maliyetini kendiliğinden garanti etmez.
Kaynak ve Yöntem Notu
Core Web Vitals eşikleri ile arama görünürlüğü açıklamaları yukarıda bağlanan Google Search, web.dev ve Next.js dokümanlarından 14 Temmuz 2026'da kontrol edildi. Format, paket ve cache karşılaştırmalarında doğrulanmamış sabit tasarruf yüzdeleri kullanılmadı. Sonuçlar gerçek kullanıcı verisiyle doğrulanmadan SEO, dönüşüm veya gelir artışı olarak sunulmamalıdır; kaynaklar Maviona'yı değerlendirmez veya onaylamaz.
Sitenizin performans darboğazlarını değerlendirmek için Maviona ile iletişime geçin.
