# CDN'de asset sürümleme: hash'leme ve cache stratejisini nasıl kurarım?

> Query-string busting'i bırakın: asset'i content-hash'li adla `immutable` cache'leyin, HTML'i kısa ömürlü tutun, canlıya geçmeden önce yükleyin.

- Soruldu: 2026-05-24
- Yanıtlandı: 2026-05-27
- Soran: Aslı
- Etiketler: performans, ci-cd, altyapi
- Kaynak: https://www.muhammetsafak.com.tr/sor-bakalim/cdn-asset-surumleme-hashleme-ve-cache-stratejisi/
- Dil: tr-TR
- Yazar: Muhammet Şafak

---
**Soru:** DeployerPHP ile yeni kodu canlıya alınca kullanıcının tarayıcısındaki eski CSS/JS yüzünden arayüz kırılıyor. `mix.js?id=123` gibi query string'i bazı CDN'ler göz ardı ediyor, eski sürümü servis etmeye devam ediyor.

Kalıcı çözüm için asset adlarını hash'leyip (`app.a8f9b2.js`) `Cache-Control: max-age=31536000` ile CDN'e göndermek istiyorum. CI/CD'de derleme ve invalidate otomasyonunu nasıl tasarlarım?


Kısa cevap: Query-string ile cache busting güvenilmez; kalıcı çözüm content-hash'li dosya adı (`app.a8f9b2.js`) — ad sadece içerik değişince değişir, gerisini cache stratejisi halleder.

Sorunun kökü şu: `app.js?id=123` desende dosya adı hep aynı. Bazı CDN'ler query string'i cache key'inden atar ya da yok sayar, dolayısıyla `id` değişse de cache'teki ESKİ dosyayı servis etmeye devam eder. Cache key'ini değiştirmeniz gerekiyor — query'yi değil, adı.

1. **Content-hash'li dosya adı kullanın.** `app.a8f9b2.js` gibi; hash dosyanın içeriğinden türer. İçerik değişince ad değişir, değişmediyse aynı kalır. Böylece her asset'i sonsuza kadar `Cache-Control: public, max-age=31536000, immutable` ile cache'leyebilirsiniz — `immutable` direktifi tarayıcıya "bunu bir daha doğrulama bile" der, gereksiz koşullu istekleri keser.
2. **Uzun cache'lenMEYECEK tek dosya: HTML/giriş noktası.** Hash'li asset'lere işaret eden HTML'i (veya manifest'i referanslayan entrypoint'i) kısa ömürlü ya da `no-cache` yapın. Mantık basit: HTML her zaman taze gelsin ki YENİ hash'lere işaret etsin; asset'ler ise hash sayesinde zaten doğru sürümü taşır. Burayı uzun cache'lerseniz tüm zincir kilitlenir.
3. **CI/CD: önce yükleyin, sonra canlıya geçin.** Vite manifest'i ile hash'li çıktı üretin. Sıra kritik: asset'leri CDN'e/bucket'a uygulamayı canlıya almadan ÖNCE yükleyin. Yoksa yeni HTML henüz yüklenmemiş bir hash'e işaret eder ve 404 alırsınız. DeployerPHP akışında bunu "symlink'i çevirmeden önce upload" adımı olarak kurun.
4. **Önceki sürümün asset'lerini bir süre tutun.** Deploy anında sayfası açık olan kullanıcı hâlâ eski HTML'i çalıştırıyor ve eski hash'leri ister. Bir önceki release'in asset'lerini silmezseniz bu "in-flight" kullanıcılar kırılmaz. DeployerPHP'nin `keep_releases` mantığı zaten size bunu verir.

**Sonuç:** Ben olsam content-hash'li, `immutable` cache'li asset + kısa ömürlü HTML + canlıya-geçmeden-önce-upload üçlüsünü kurardım. Gerçek content hashing'de pratikte asset purge'üne neredeyse hiç ihtiyacınız olmaz — ad değiştiği için eski dosya zaten dokunulmadan kalır, kimse onu istemez. Tek invalidate etmeniz gereken şey HTML'dir, o da zaten kısa cache'li. Query-string busting'i tamamen bırakın.

## İlgili Yazılar

- [CI/CD'de OIDC ve IAM Role ile şifresiz (secretless) AWS erişimini nasıl kurarım?](https://www.muhammetsafak.com.tr/sor-bakalim/ci-cd-de-secret-yonetimi-ve-oidc-ile-sifresiz-erisim/) — Sor Bakalım
- [Docker imaj boyutunu multi-stage build ve distroless ile nasıl küçültürüm?](https://www.muhammetsafak.com.tr/sor-bakalim/docker-imaj-boyutunu-multi-stage-ve-distroless-ile-kucultmek/) — Sor Bakalım
- [Terraform state'i S3 + DynamoDB locking ile nasıl güvenli yönetirim?](https://www.muhammetsafak.com.tr/sor-bakalim/terraform-state-yonetimi-s3-ve-dynamodb-ile-locking/) — Sor Bakalım
