# CI/CD'de veritabanı göçlerini (migrations) güvenli nasıl çalıştırırım?

> Kolonu nullable ekleyip backfill'i ayrı throttle'lı bir adıma alın, migration'ı deploy'dan ayrı bir aşamada koşturun, eskiyi sonraki release'te düşürün.

- Soruldu: 2026-06-11
- Yanıtlandı: 2026-06-12
- Soran: Melih
- Etiketler: ci-cd, veritabani, laravel
- Kaynak: https://www.muhammetsafak.com.tr/sor-bakalim/ci-cd-de-veritabani-goclerini-guvenli-calistirmak/
- Dil: tr-TR
- Yazar: Muhammet Şafak

---
**Soru:** CI/CD sürecimizde `php artisan migrate` deployment adımları arasında otomatik çalışıyor. Bir migration çok büyük bir tabloya kolon eklerse ve uzun sürerse pipeline timeout'a düşüyor; ya da o sırada canlıda olan eski kod, DB değişikliği yüzünden hata vermeye başlıyor.

Büyük projelerde "backward-compatible migration" prensiplerini CI/CD akışında nasıl uygularım?


Kısa cevap: Asıl hata, şema değişikliğini eski kod hâlâ canlıyken deploy'a sıkı sıkıya bağlamak — çözüm, geriye uyumlu (expand/contract) migration'ları kod deploy'undan **ayırmak**.

Problemi netleştirelim: ya eski kod yeni şemayla karşılaşıp patlıyor, ya da büyük bir `ALTER` tabloyu kilitleyip pipeline'ı timeout'a düşürüyor. İkisi de aynı kökten — kuplaj.

1. **Expand/contract disiplinini benimse.** Aynı release'de bir kolonu ekleyip onu gerektiren kodu deploy etme; asla rename/drop'u kullanan release ile aynı anda yapma. Önce kolonu **nullable** ekle, sonra "hem eskiye hem yeniye yazan" kodu deploy et, en son ayrı bir release ile eskiyi kaldır.
2. **Backfill'i request yolundan ve deploy adımından çıkar.** Büyük tabloyu doldurma işini ayrı, **throttle'lı** bir adımda yap — deploy adımının transaction'ı içinde değil. Aksi halde tek bir dev `UPDATE` hem kilitler hem timeout'a sokar.
3. **Migration'ı kendi pipeline aşaması yap, timeout baskısı olmadan.** Şema değişikliğini app deploy'undan ayrı bir stage'e al. Büyük/kilitleyici değişiklikler için `pt-online-schema-change` / `gh-ost` gibi online-DDL araçlarıyla **bant dışı** çalıştır; tabloyu kilitlemeden kolonu ekler.
4. **İdempotent ve geri alınabilir yaz, deploy'u migration'a gate'le.** Migration tekrar çalıştığında bozulmasın, geri dönüşü olsun. Deploy'u migration başarısına bağla; ama yıkıcı adımları (drop, rename) yeni kod tamamen yayıldıktan sonraki bir follow-up release'e bırak.

**Sonuç:** Ben olsam expand/contract'ı kural yapar, migration'ları app deploy'undan ayırır ve büyük/kilitleyici değişiklikleri online araçlarla kritik yolun dışında çalıştırırdım. Şema değişikliğini hiçbir zaman "deploy'un ortasında, eski kod canlıyken" yapma — onu kademeli ve geriye uyumlu yürüt; pipeline timeout'u da, eski kodun patlaması da o zaman ortadan kalkar.

## İlgili Yazılar

- [DeployerPHP zero-downtime deploy'da OPcache'ten gelen 500 hatalarını nasıl engellerim?](https://www.muhammetsafak.com.tr/sor-bakalim/deployerphp-ile-sifir-kesinti-deploy-ve-opcache-temizligi/) — Sor Bakalım
- [Canlı tabloda dual-write ile sıfır kayıplı şema geçişini nasıl koordine ederim?](https://www.muhammetsafak.com.tr/sor-bakalim/canli-tabloda-dual-write-ile-sifir-kayipli-sema-gecisi/) — Sor Bakalım
- [İşlediğim satırları aynı anda güncellerken chunk yerine chunkById mı kullanmalıyım?](https://www.muhammetsafak.com.tr/sor-bakalim/isledigim-satirlari-ayni-anda-guncellerken-chunk-yerine-chunkbyid-mi-kullanmaliyim/) — Sor Bakalım
