Cache-Control: no-cache başlığını ilk gören çoğu geliştirici bu direktifin önbelleği tamamen devre dışı bıraktığını varsayar. İsim tam da bunu çağrıştırıyor. Oysa no-cache, "önbelleğe alma" değil, "önce doğrula" anlamına gelir. Tarayıcı varlığı önbelleğe alır; ama kullanmadan önce sunucuya sorar. Bu tek yanlış anlamanın bedeli, binlerce gereksiz tam HTTP isteği veya tam tersi — güncellenmesi gereken varlıkların günlerce eski haliyle sunulması olabilir.

HTTP önbellekleme iki ayrı mekanizmadan oluşur: tazelik (freshness) ve doğrulama (validation). Tazelik, önbelleğe alınan bir varlığın ne kadar süre geçerli sayılacağını belirler — max-age ve immutable gibi direktifler bu katmanı yönetir. Doğrulama ise tazelik süresi dolduğunda tarayıcının sunucuya "bu dosya değişti mi?" diye sorma biçimidir — burada devreye ETag ve Last-Modified başlıkları girer. Bu iki katmanı birbirine karıştırmak, önbellekleme yapılandırmasını hem verimsiz hem de hata üretmeye açık hale getirir.

Cache-Control direktifleri ve doğrulama başlıkları ayrı çalışıyor gibi görünse de aralarındaki etkileşim performans açısından çok belirleyicidir. Yanlış bir direktif kombinasyonu, max-age süresi dolmadan hiç kullanılmayan önbellekler ya da sunucuya gereksiz yük bindiren doğrulama istekleri doğurabilir. Tarayıcı önbellekleme konusunu daha önce ele almıştık; bu yazı o temelin üzerinde Cache-Control ile ETag'ın birlikte nasıl çalıştığını derinlemesine inceler.

"no-cache" önbelleği devre dışı bırakmaz — doğrulamayı zorunlu kılar

Cache-Control: no-cache ve Cache-Control: no-store sıklıkla birbirinin yerine kullanılır; ama ikisi farklı şeyler yapar.

no-cache direktifiyle gelen bir yanıt tarayıcı tarafından önbelleğe alınır — ama her kullanımdan önce sunucuya koşullu bir istek gönderilir. Sunucu "değişmedi" derse 304 yanıtıyla yanıt verir; tarayıcı önbellekteki kopyayı kullanır. 304 yanıtı yalnızca başlık (header) içerir, gövde (body) taşımaz. Tipik bir 304 yanıtı 150–300 byte civarındadır; aynı kaynağın tam yanıtı megabaytlarla ölçülebilir. Bant genişliği açısından ciddi tasarruf sağlar. Ağ gidiş-dönüş süresi (RTT) hâlâ gereklidir; ama transfer maliyeti minimumdur.

no-store ise gerçek anlamda önbelleğe alma yapmaz. Her istekte tam indirme gerçekleşir: sunucudan 200 yanıtı, tam body. Gerçekten hassas kişisel veri içeren sayfalar — banka ekstresi, tıbbi rapor, tek kullanımlık işlem kodu — için no-store anlamlıdır. "Bu sayfa güncel kalsın" amacıyla HTML dosyalarına no-store uygulamak ise her sayfa yüklemesinde tam transfer maliyeti demektir. Çoğu durumda no-cache yeterlidir ve çok daha verimlidir.

Bu iki direktif arasındaki seçim pratikte şu soruya bağlıdır: içerik kullanıcıya özel ve kesinlikle hiçbir ara noktada saklanmamalı mı? Evet ise no-store. Sadece her zaman güncel olması yeterliyse no-cache.

max-age dolduğunda tarayıcının başlattığı koşullu istek döngüsü

Cache-Control: max-age=3600 direktifi tarayıcıya "bu yanıtı 1 saat taze kabul et" der. O süre boyunca tarayıcı aynı URL için herhangi bir ağ isteği göndermez; önbellekteki kopyayı doğrudan kullanır. 1 saat dolduğunda varlık "bayat" (stale) hale gelir.

Bayat bir varlık için tarayıcı sunucuya koşullu istek gönderir. Bu isteğin başlığına If-None-Match veya If-Modified-Since eklenir. Sunucu varlığın değişmediğini belirlerse 304 döner, tarayıcı önbellekteki kopyayı kullanmaya devam eder. Sunucu içeriğin güncellendiğini belirlerse 200 ve yeni içerik döner. Bu döngü, tazelik süresi bittikten sonra her istekte tekrarlanır.

s-maxage direktifi, CDN katmanı için tarayıcıdan bağımsız bir süre belirlemeyi sağlar. Cache-Control: max-age=60, s-maxage=86400 yapılandırması tarayıcıya "1 dakika taze tut" derken CDN'e "24 saat taze tut" demektir. Sık güncellenen ama kullanıcı bazlı kişiselleştirme içermeyen içerik — haber akışı, ürün listesi, kategori sayfaları — için bu kombinasyon pratik bir denge sağlar. CDN saatte değil, günde bir kez sunucuya gider; tarayıcı ise daha kısa sürede güncel içeriği alır.

ETag ile Last-Modified: doğrulama mekanizmasının iki aracı

Sunucu ETag başlığıyla bir varlığa içerik bazlı parmak izi atar. Genellikle dosyanın hash değeri veya versiyon numarası kullanılır: ETag: "a3f4b2c1d5e6". Tarayıcı koşullu istekte bu değeri If-None-Match: "a3f4b2c1d5e6" olarak geri gönderir. Sunucu mevcut ETag'ı hesaplayıp karşılaştırır; eşleşiyorsa 304 döner.

Last-Modified ise zaman damgasına dayalı daha basit bir mekanizmadır: Last-Modified: Thu, 03 Apr 2026 08:00:00 GMT. Tarayıcı bunu If-Modified-Since olarak geri gönderir. Sunucu dosyanın o tarihten sonra değişip değişmediğine bakar. İkisi aynı yanıtta birlikte gelebilir; bu durumda tarayıcı ETag'ı önceliklendirir. Last-Modified saniye hassasiyetiyle çalışır — aynı saniye içinde değişen dosyaları ayırt edemez. ETag bu senaryoda doğru sonuç verir.

Güçlü ETag ile zayıf ETag arasında da bir ayrım vardır. Zayıf ETag (W/"a3f4b2c1") "semantik olarak eşdeğer" anlamına gelir; güçlü ETag byte byte özdeşliği garantiler. Byte-range istekleri — büyük video dosyaları veya sürdürülebilir indirmeler — yalnızca güçlü ETag ile doğru çalışır. Nginx ve Apache, ETag hesabını dosya istatistiklerine (inode, boyut, değiştirilme zamanı) dayandırarak optimize eder; içeriğin tamamını okumaz. Dinamik içerik üreten uygulamalarda ETag'ı manuel yönetmek gerekiyorsa bu hesaplama maliyeti göz önünde bulundurulmalıdır.

immutable direktifi ve içerik hash stratejisi

Cache-Control: public, max-age=31536000, immutable kombinasyonu "bu dosyayı 1 yıl önbelleğe al ve bu süre boyunca hiçbir koşullu istek gönderme" anlamına gelir. immutable direktifi tarayıcıya max-age süresi dolmadan doğrulama isteği gönderme talimatını verir. Normal şartlarda kullanıcı sayfayı yenilediğinde (soft reload) tarayıcı koşullu istek gönderebilir; immutable bu davranışı da engeller.

Bu yapılandırma content hash ile versiyonlanan varlıklar için biçilmiş kaftandır. main.a3f4b2c1.js gibi dosya adları, içerik değiştiğinde URL'nin de değişeceğini garanti eder. Önbellekte kalan eski dosya asla yanlış içerik sunmaz — çünkü yeni deploy'da farklı bir URL kullanılır. CSS ve JavaScript küçültme ile code splitting pipeline'ına bu önbellekleme stratejisini eklemek, tekrar eden ziyaretçiler için ağ isteği sayısını sıfıra yaklaştırabilir. 500 KB'lık bir JS bundle için bu, her sayfada kazanılan 50–200 ms demektir.

immutable şu an Firefox ve Chromium tabanlı tarayıcılar tarafından desteklenmektedir. Desteklemeyen tarayıcılar bu direktifi yoksayar ve max-age süresince normal davranışlarını sürdürür — geriye dönük uyumluluk sorun yaratmaz. HTML dosyaları için ise immutable uygun değildir; HTML'nin URL'si değişmez ve her yeni deploy'da tarayıcının güncel sürümü alması gerekir. HTML için doğru yapılandırma no-cache ya da çok kısa bir max-age değeridir.

CDN katmanında s-maxage ve private direktiflerinin etkisi

CDN önbellekleme, tarayıcı önbelleklemesinden yapısal olarak farklı çalışır. Tarayıcı önbelleği tek kullanıcıya aittir; CDN önbelleği aynı anda binlerce kullanıcıya hizmet verebilir. Bu fark, direktif seçimini doğrudan etkiler.

Cache-Control: private direktifi CDN'lere "bu yanıtı önbelleğe alma, yalnızca kullanıcının kendi tarayıcısına özel" sinyali verir. Kişiselleştirilmiş içerik — kullanıcı adı, sepet bilgisi, oturum durumu — private olmadan CDN önbelleğine düşer ve farklı kullanıcılara yanlış içerik sunulabilir. Bu ciddi bir güvenlik meselesidir ve pratikte az rastlanan ama sonuçları ağır bir yapılandırma hatasıdır.

s-maxage ile CDN TTL'ini tarayıcıdan bağımsız ayarlamak, TTFB değerlerini özellikle coğrafi olarak dağıtılmış kullanıcılarda belirgin biçimde düşürür. CDN'den dönen önbelleklenmiş yanıt, kaynak sunucuya giden tam istekten 100–500 ms daha hızlı olabilir. Cache-Control: max-age=0, s-maxage=3600 yapılandırması tarayıcıya "her zaman doğrula" derken CDN'e "1 saat taze tut" der. Bu sayede kullanıcılar CDN'den hızlı yanıt alırken CDN de yalnızca saatte bir sunucuya gider.

Deploy sonrası CDN invalidation ayrı bir dikkat gerektirir. s-maxage süresi dolmadan içerik güncellendiyse CDN'deki eski kopya geçersiz kılınmalıdır. Hangi URL'lerin veya cache tag'larının invalidate edileceğini önceden planlamak — özellikle büyük deploy'larda — önbellekleme kazancını yitirmeden güncel içerik sunmanın anahtarıdır. Preload ve prefetch gibi kaynak ipuçlarıyla birleştirildiğinde CDN ve tarayıcı önbelleklemesi güçlü bir katmanlı sistem oluşturur.

Tazelik ve doğrulama: bu iki kavramı birbirinden ayırt etmek, önbellekleme yapılandırmasındaki çoğu hatayı baştan engeller. max-age ve immutable tazelik kararlarıdır — tarayıcıya ne kadar süre sunucuya sormadan kullanabileceğini söyler. ETag ve Last-Modified ise doğrulama araçlarıdır — tazelik süresi dolduğunda "değişmedi" onayını bant genişliği harcamadan alır.

Varlık türüne göre bir strateji şu şekilde kurulabilir: HTML dosyaları için no-cache — içerik her zaman doğrulansın, ama 304 ile verimli biçimde. Versiyonlanmış CSS ve JavaScript bundle'ları için public, max-age=31536000, immutable — URL değişince yeni dosya, değişmeyince önbellekteki kopya. API yanıtları için private, no-cache veya s-maxage ile CDN katmanı — kullanıcı verisi korunurken genel içerik CDN'den sunulsun.

Doğru yapılandırılmış önbellekleme yalnızca bant genişliği tasarrufu sağlamaz. LCP gibi gerçek kullanıcı metrikleri üzerinde doğrudan etkisi vardır. Önbellekten dönen yanıt sunucuya gidip gelmekten kaçındığı için bu kazanç, özellikle mobil ve yüksek gecikmeli bağlantılarda kullanıcı deneyimine somut olarak yansır.