Diyelim ki bir JavaScript dosyasına Cache-Control: public, max-age=31536000 uyguladınız — 1 yıllık önbellek. Kullanıcı sayfayı ziyaret etti, dosya önbelleğe alındı. Bir hafta sonra o dosyada kritik bir hata düzelttiniz ve yeni sürümü deploy ettiniz. Aynı URL'de sunulan bu dosyanın önbelleği tarayıcıda hâlâ geçerli. Kullanıcı eski, hatalı sürümü görmeye devam eder. 51 hafta boyunca.

Sizi bu kilitlenmeden kurtaracak araç immutable direktifi değil — doğru soruyu sormak. immutable, "bu dosya URL'si yaşadığı sürece hiçbir zaman değişmeyecek" garantisini tarayıcıya verir. Bu garantiyi vermenin tek güvenli yolu, içerik değiştiğinde URL'nin de değişmesini sağlamaktır. Bu koşul sağlanmadan immutable uygulamak, yukarıdaki senaryoyu 1 yıllık önbellekten geri dönüşü olmayan bir kilitlenmeye dönüştürür.

Peki bu koşul sağlandığında immutable ne kazandırır, nasıl çalışır ve hangi varlık türleri için gerçekten uygundur? Bu sorular, statik varlık önbellekleme stratejisinin özüdür.

immutable direktifi tarayıcıya tam olarak ne söyler

Normal max-age önbelleklemesinde tarayıcı, süre dolmadan önce bile bazı durumlarda sunucuya doğrulama isteği gönderebilir. En yaygın tetikleyici kullanıcının sayfayı yenilemesidir (F5 veya Ctrl+R). Soft reload sırasında tarayıcı, max-age süresi dolmamış olsa bile önbellekteki varlıklar için koşullu istek gönderebilir — "bu dosya hâlâ geçerli mi?" diye sorar. Sunucu 304 yanıtı döndürür, dosya yeniden indirilmez; ama ağ gidiş-dönüşü harcandı.

immutable direktifi bu davranışı engeller. Tarayıcıya şunu söyler: "Bu dosyanın içeriği asla değişmez. max-age süresi boyunca hiçbir koşulda sunucuya sormaya gerek yok." Kullanıcı sayfayı yenilese bile, doğrulama isteği gönderilmez; önbellekteki kopya doğrudan kullanılır. Yalnızca hard reload (Ctrl+Shift+R veya Shift+F5) bu davranışı atlatır.

Pratikte fark küçük görünebilir — sonuçta 304 yanıtı zaten içerik indirmiyor. Ama yüksek trafikli bir sitede onlarca statik varlık için bu gereksiz doğrulama istekleri birikir. Özellikle max-age=31536000 ile birlikte kullanılan immutable, tekrar eden ziyaretçiler için ilk byte süresini (TTFB) sıfıra yaklaştırır — dosya önbellekte varsa ağa hiç çıkılmaz. Mobil bağlantılarda bu her varlık başına 50–150 ms tasarruf anlamına gelebilir.

Content hash olmadan immutable kullanmak neden tehlikelidir

immutable direktifi, içerik değiştiğinde URL'nin değişeceğini varsayar. Bu varsayım sağlanmıyorsa sistem kırılır ve tarayıcı düzeyinde onarılması mümkün değildir.

Sorunun boyutunu somutlaştıralım. Kullanıcı main.js dosyasını immutable ile önbelleğe aldı. Siz dosyayı sunucuda güncellediniz. Tarayıcı max-age süresi dolana kadar — 1 yıl ayarladıysanız 1 yıl — bu dosyayı bir kez bile sunucudan sorgulamaz. Hard reload olmadığı sürece güncelleme görünmez. Kullanıcıyı hard reload yapmaya yönlendirmek ise çoğu kullanıcının bilmediği veya yapmayacağı bir işlemdir.

Content hash, bu sorunu URL katmanında çözer. Build araçları (webpack, vite, rollup) çıktı dosyalarını main.a3f4b2c1.js biçiminde adlandırır; hash, dosya içeriğinden türetilir. İçerik değiştiğinde hash değişir, dolayısıyla URL değişir. Eski URL ile yeni URL tamamen ayrı varlıklardır. Eski önbellekteki kopya hiçbir zaman yanlış içerik sunmaz; yeni URL için önbellek henüz oluşmamıştır, tarayıcı indirir.

Bu yüzden immutable yalnızca hash içeren dosya adlarıyla anlamlıdır: Cache-Control: public, max-age=31536000, immutable direktifi style.b7c9d2e1.css için güvenlidir; style.css için değildir.

Hangi varlık türleri immutable için uygundur

Versiyonlanmış statik varlıklar — content hash içeren JavaScript bundle'ları, CSS dosyaları, font dosyaları ve görsel varlıklar — immutable için birincil adaylardır. Tree shaking ve code splitting ile üretilen chunk dosyaları da bu kategoriye girer; her chunk kendi hash'iyle adlandırılır.

Font dosyaları özellikle iyi bir adaydır. woff2 dosyaları nadiren değişir ve genellikle versiyon numarasıyla veya hash ile yönetilir. Font yükleme optimizasyonu açısından bakıldığında, bir kez indirilen ve önbellekte sonsuza kadar kalan font dosyası, tekrar eden ziyaretçiler için render bloklama süresini sıfıra düşürür.

Görsel varlıklar için durum daha nüanslıdır. Logolar ve ikonlar gibi nadiren değişen görseller hash ile versiyonlanabilir ve immutable alabilir. Ürün fotoğrafları veya içerik görselleri ise çoğunlukla aynı URL'de güncellenir — bu durumda immutable uygun değildir, daha kısa max-age veya no-cache tercih edilmelidir.

HTML dosyaları immutable için kesinlikle uygun değildir. HTML'nin URL'si değişmez; her yeni deploy'da tarayıcının güncel sürümü alması gerekir. HTML için doğru yapılandırma Cache-Control: no-cache veya en fazla birkaç dakikalık max-age değeridir. API yanıtları da aynı gerekçeyle immutable dışında tutulmalıdır.

Build pipeline'ında immutable stratejisini kurmak

Modern build araçları content hash üretimini varsayılan olarak destekler. Vite'da çıktı dosyası adlandırması vite.config.js üzerinden yapılandırılır:

// vite.config.js
export default {
  build: {
    rollupOptions: {
      output: {
        entryFileNames: 'assets/[name].[hash].js',
        chunkFileNames: 'assets/[name].[hash].js',
        assetFileNames: 'assets/[name].[hash][extname]'
      }
    }
  }
}

Bu yapılandırmayla üretilen her dosya içerik bazlı bir hash alır. Sunucu tarafında bu dosyalar için Cache-Control: public, max-age=31536000, immutable başlığını döndürmek yeterlidir. Apache'de .htaccess ile pattern eşleşmesi üzerinden uygulanabilir, Nginx'te location bloğuyla. CDN katmanında aynı başlık, edge önbelleklemesi için geçerlidir; s-maxage eklemek CDN TTL'ini ayrıca kontrol etmeye olanak tanır.

HTML dosyasının her zaman güncel kalması için farklı bir yapılandırma gerekir. HTML, versiyonlanmış varlıklara referans verir — script ve link etiketlerindeki hash'li URL'ler aracılığıyla. HTML güncellendiğinde tarayıcı onu indirir; o HTML içindeki hash'li varlıklar ise zaten önbellektedir, yeniden indirilmez. Bu katmanlı yapı, hem güncellik hem de maksimum önbellekleme verimliliğini aynı anda sağlar.

immutable direktifinin tarayıcı desteği ve gerçek davranışı

immutable direktifi Firefox (49+) ve Chromium tabanlı tarayıcılar (Chrome, Edge, Brave) tarafından desteklenmektedir. Safari desteği sınırlı ve tutarsız olmuştur; Safari 17 ile iyileşme raporlanmış olsa da güvenilir davranış henüz evrensel değildir. Desteklemeyen tarayıcılar direktifi yoksayar ve standart max-age davranışını sürdürür — soft reload sırasında koşullu istek gönderebilirler. Bu geriye dönük uyumluluk sorun yaratmaz; yalnızca o tarayıcılar için performans avantajı azalır.

Tarayıcının immutable direktifini gerçekten uygulayıp uygulamadığını doğrulamak için Chrome DevTools Network sekmesinde önbellek davranışını incelemek yeterlidir. Sayfayı soft reload ettiğinizde, immutable direktifli varlıklar "(disk cache)" veya "(memory cache)" olarak görünür; ağ isteği gönderilmez. Normal max-age'li varlıklar ise reload sırasında 304 isteği üretebilir.

Tarayıcı önbellekleme stratejisinin tamamına bakıldığında immutable, doğru koşulda uygulandığında en agresif ve en verimli seçenektir. Ağ isteği sıfır, transfer sıfır, gecikme sıfır — dosya önbellekte olduğu sürece. Bu verimliliğin bedeli, URL yönetiminde hata payı bırakmamaktır.

Önbellek stratejisi tek bir direktif seçmekten ibaret değildir. HTML, versiyonlanmış JS/CSS, fontlar, API yanıtları — her varlık türü farklı bir tazelik ve doğrulama dengesi gerektirir. immutable bu denkleme, "değişmeyeceğinden emin olduğun şeyi sonsuza kadar önbellekte tut" boyutunu katar. Emin olamadığın her şey için daha kısa süreler veya doğrulama mekanizmaları devreye girer. İkisi birlikte, tekrar eden ziyaretçiler için ağ yükünü minimuma indiren katmanlı bir sistem oluşturur.