---
title: "Supabase Migration Sistemi: Sıfırdan Production'a Güvenli Geçiş"
description: "Supabase migration nasıl yönetilir? supabase db diff, db push, RLS migration'ları, rollback stratejisi ve 80+ migration'lık projede dersler."
date: 2026-04-13
category: devops
tags: ["supabase", "migration", "veritabani", "deployment", "devops", "postgresql"]
url: https://mikroerp.dev/blog/supabase-migration-rehberi/
---

## Neden Migration?

Veritabanı şemanızı "elle" değiştirmek tehlikelidir. Migration sistemi:
- Değişiklikleri **versiyonlar** (git gibi)
- **Tekrarlanabilir** — her ortamda aynı sonuç
- **Geri alınabilir** — hata yaparsanız rollback
- **Paylaşılabilir** — ekipteki herkes aynı şemayı çalıştırır

## Supabase CLI Kurulumu

```bash
npm install supabase --save-dev
npx supabase init
npx supabase login
npx supabase link --project-ref YOUR_PROJECT_REF
```

## Migration Oluşturma Yöntemleri

### 1. Manuel Oluşturma

```bash
npx supabase migration new create_orders_table
```

```sql
-- supabase/migrations/20240415120000_create_orders_table.sql
CREATE TABLE orders (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  customer_id UUID REFERENCES customers(id),
  total_amount NUMERIC(12,2) NOT NULL DEFAULT 0,
  status TEXT DEFAULT 'pending',
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

ALTER TABLE orders ENABLE ROW LEVEL SECURITY;

CREATE POLICY "users_read_own_orders" ON orders
  FOR SELECT USING (customer_id = auth.uid());
```

### 2. Otomatik diff (Dashboard değişikliklerini yakala)

```bash
# Dashboard'da yaptığınız değişiklikleri migration'a çevir
npx supabase db diff --use-migra -f add_phone_to_customers

# Oluşturulan dosya:
# supabase/migrations/20240415130000_add_phone_to_customers.sql
```

## Migration Çalıştırma

```bash
# Local veritabanına uygula
npx supabase db push

# Local'i sıfırla ve tüm migration'ları baştan çalıştır
npx supabase db reset

# Migration durumunu kontrol et
npx supabase migration list
```

## Migration Dosyası Anatomisi

```
supabase/
├── migrations/
│   ├── 20240101_initial_schema.sql
│   ├── 20240215_add_rls_policies.sql
│   ├── 20240310_create_audit_system.sql
│   └── 20240415_add_orders_table.sql
├── seed.sql          ← Test verisi
└── config.toml       ← Proje ayarları
```

**Kurallar:**
- Oluşturulmuş migration'ı **asla düzenlemeyin**
- Yeni değişiklik = yeni migration dosyası
- Dosya adında timestamp zorunlu (sıralama için)

## RLS Politikalarını Migration'a Dahil Etme

```sql
-- 20240415_orders_rls.sql
-- Tablo RLS'i etkinleştir
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;

-- Okuma politikası
CREATE POLICY "authenticated_read" ON orders
  FOR SELECT
  TO authenticated
  USING (
    customer_id = auth.uid()
    OR (auth.jwt() -> 'app_metadata' ->> 'role') = 'admin'
  );

-- Yazma politikası
CREATE POLICY "owner_insert" ON orders
  FOR INSERT
  TO authenticated
  WITH CHECK (customer_id = auth.uid());

-- Güncelleme politikası
CREATE POLICY "owner_update" ON orders
  FOR UPDATE
  TO authenticated
  USING (customer_id = auth.uid())
  WITH CHECK (customer_id = auth.uid());
```

## Rollback Stratejisi

Supabase CLI'de otomatik rollback yoktur. Manuel rollback migration'ları yazın:

```sql
-- 20240416_rollback_orders.sql (gerekirse)
DROP POLICY IF EXISTS "authenticated_read" ON orders;
DROP POLICY IF EXISTS "owner_insert" ON orders;
DROP TABLE IF EXISTS orders;
```

**Production'da güvenli yaklaşım:**
1. Önce staging'de test edin
2. Additive migration'lar tercih edin (DROP yerine ALTER ADD)
3. Geri dönülemez değişiklikleri (DROP COLUMN) ayrı migration'da yapın

## CI/CD'de Migration

```yaml
# GitHub Actions
name: Deploy Migrations
on:
  push:
    branches: [main]
    paths: ['supabase/migrations/**']

jobs:
  migrate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: supabase/setup-cli@v1
      - run: supabase link --project-ref ${{ secrets.SUPABASE_PROJECT_REF }}
      - run: supabase db push
        env:
          SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
```

## Dikkat Edilecekler

1. **Production'da `db reset` YAPMAYIN**: Tüm veriyi siler. Sadece `db push` kullanın.
2. **Sıralama önemli**: Migration'lar timestamp sırasına göre çalışır.
3. **Idempotent yazın**: `IF NOT EXISTS`, `IF EXISTS` kullanın.
4. **Seed data**: Test verisi `seed.sql`'de tutun, migration'da değil.

## İlgili Yazılar

- [Docker + SQL Server](/blog/docker-compose-sql-server-nodejs-gelistirme/) — Local dev ortamı
- [.env Güvenli Yönetimi](/blog/env-dosyalari-guvenli-yonetim/) — Migration secrets
- [PostgreSQL Merkezi Audit Log](/blog/postgresql-merkezi-audit-log-sistemi/) — Audit migration'ları
- [Supabase RLS](/blog/supabase-rls-cok-katmanli-yetkilendirme/) — RLS policy migration'ları

---

*Bu rehber [Supabase Migration Docs](https://supabase.com/docs/guides/cli/local-development#database-migrations) dokümantasyonuna dayanarak hazırlanmıştır.*