yigityalim/x/github/işe al/paylaş
El Kitaplarına Dön

Turborepo ile Monorepo Mimarisi

Turborepo monorepoları için opinionated bir üretim referansı — workspace yapısı, iç paketler, görev grafiği tasarımı, önbellekleme, ortam değişkenleri, CI/CD ve deploy stratejileri. Turborepo 2.9 baz alınmıştır. Tutorial değil.

Son güncelleme: 2026-04-20

Teknoloji Yığını

TurborepoTypeScriptNext.jsBunVercelGitHub Actions

Bağlantılar

GitHub
ÖncekiSupabase Üretim RehberiSonrakiNext.js App Router El Kitabı
© 2026 Yiğit Yalım. Tüm hakları saklıdır.
/

Bu referans, 2022'den bu yana her projede Turborepo çalıştırarak oluşturuldu — iki uygulamalı bir portfolyo monoreposundan 10 uygulama ve 14 paketle 600K LOC'luk bir AI platformuna kadar. Buradaki kalıplar, gerçek kod tabanlarıyla temas halinde hayatta kalanlar.

Her bölüm tek bir soruyu yanıtlar: Bunu üretim için gerçekten nasıl tasarlarım?

Turborepo 2.9 (Mart 2026) kapsar. Önemli yeni özellikler: İlk Göreve Kadar Sürede %96'ya kadar iyileştirme, turbo query kararlı, turbo.jsonc desteği, OpenTelemetry (deneysel), yapılandırılmış loglama (--json, --log-file), 3.0 geçişi için Future Flags.


İçindekiler

  1. Neden Monorepo?
  2. Workspace Yapısı
  3. İç Paketler
  4. Görevleri Yapılandırma
  5. Önbellekleme
  6. Ortam Değişkenleri
  7. Geliştirme İş Akışı
  8. CI/CD
  9. Paylaşılan Yapılandırma Paketleri
  10. Deploy Stratejileri
  11. Araç Referansı

1. Neden Monorepo?

Bir monorepo, karmaşıklığını yalnızca birden fazla uygulama arasında paylaşılması gereken kodun bulunduğu durumlarda karşılıyor. Uygulamalarınız minimum paylaşılan kodla bağımsız olarak gelişiyorsa, ayrı repolar daha basittir.

Monorepo ne zaman kullanılır:

✅ Birden fazla uygulama UI bileşenlerini, hook'ları, tipleri veya yardımcıları paylaşıyor
✅ Tek bir PR'ın paylaşılan bir paketi ve tüm tüketicilerini eş zamanlı güncellemesini istiyorsun
✅ Birleşik TypeScript, ESLint ve Prettier yapılandırması istiyorsun
✅ Atomik çapraz paket değişikliklerine ihtiyacın var

❌ Uygulamalar gerçekten bağımsız (farklı ekipler, farklı deploy döngüleri)
❌ Tek bir uygulaman var ve daha fazlası için planın yok
❌ Paylaşılan kod bir npm paketi olarak daha iyi olur

Monorepo vergisi: başlangıç kurulum karmaşıklığı, CI yapılandırma yükü ve zaman zaman şaşırtıcı önbellek davranışı. Bunlar gerçek maliyetler — faydaların durumun gerektirdiğinden ağır basıp basmadığı konusunda dürüst ol.


2. Workspace Yapısı

Dizin Düzeni

benim-monorepo/
├── apps/              # Uygulamalar — deploy edilir, diğer paketlere kurulmaz
│   ├── web/           # Next.js frontend
│   ├── docs/          # Dokümantasyon sitesi
│   └── api/           # Backend API
├── packages/          # Kütüphaneler ve araçlar — uygulamalara ve birbirine kurulur
│   ├── ui/            # Paylaşılan React bileşenleri
│   ├── config-ts/     # Paylaşılan TypeScript yapılandırması
│   ├── config-eslint/ # Paylaşılan ESLint yapılandırması
│   └── utils/         # Paylaşılan yardımcılar
├── package.json       # Kök — workspace tanımı + repo yönetimi devDependencies
├── turbo.json         # Görev pipeline tanımı
└── pnpm-workspace.yaml (veya bun.lockb / .npmrc npm/yarn için)

apps/ ve packages/ ayrımı bir kuraldır, zorunluluk değil. Önemli olan: uygulamalar deploy edilir ve diğer paketler tarafından import edilmez; paketler ise uygulamalar ve diğer paketler tarafından import edilen kütüphanelerdir.

Workspace Yapılandırması

pnpm (pnpm-workspace.yaml):

packages:
  - "apps/*"
  - "packages/*"

Bun (package.json):

{
  "workspaces": ["apps/*", "packages/*"]
}

npm/yarn (package.json):

{
  "workspaces": ["apps/*", "packages/*"]
}

Kök package.json

Kök, yalnızca repo yönetim araçları içindir — uygulama bağımlılıkları değil:

{
  "name": "benim-monorepo",
  "private": true,
  "scripts": {
    "build": "turbo build",
    "dev": "turbo dev",
    "lint": "turbo lint",
    "check-types": "turbo check-types",
    "test": "turbo test",
    "format": "prettier --write \"**/*.{ts,tsx,md}\""
  },
  "devDependencies": {
    "turbo": "latest",
    "prettier": "^3.0.0"
  },
  "packageManager": "pnpm@9.0.0"
}

packageManager alanı önemlidir — Turborepo bunu paket yöneticisini tespit etmek ve lockfile ayrıştırmayı kararlı hale getirmek için kullanır. Bu olmadan, önbellek geçersiz kılma öngörülemeyen olabilir.

.gitignore eklemeleri

.turbo
node_modules
dist
.next
out

3. İç Paketler

Üç Strateji

Workspace içindeki iç paketler (kütüphaneler) üç şekilde yapılandırılabilir:

1. Just-in-Time (JIT) / Tüketici Tarafından Derlenen

Build adımı yok. Tüketicinin bundler'ı (Next.js, Vite vb.) TypeScript'i doğrudan derler.

// packages/ui/package.json
{
  "name": "@repo/ui",
  "exports": {
    ".": "./src/index.tsx"  // doğrudan kaynağa işaret eder
  },
  "devDependencies": {
    "typescript": "^5.0.0",
    "react": "^19.0.0"
  }
}

Artıları: Sıfır build adımı, en hızlı iterasyon, dist/ konusunda endişe yok.

Eksileri: Yalnızca her tüketici TypeScript anlayan bir bundler kullandığında çalışır. Turborepo tarafından önbelleğe alınamaz (build çıktısı yok). TypeScript'te compilerOptions.paths kullanılamaz.

2. Derlenmiş Paket

Kendi build adımı var. Turborepo build çıktısını önbelleğe alabilir.

// packages/utils/package.json
{
  "name": "@repo/utils",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "default": "./dist/index.js"
    }
  },
  "scripts": {
    "build": "tsc",
    "dev": "tsc --watch",
    "check-types": "tsc --noEmit"
  },
  "devDependencies": {
    "typescript": "^5.0.0"
  }
}
// packages/utils/tsconfig.json
{
  "extends": "@repo/config-ts/base.json",
  "compilerOptions": {
    "outDir": "dist",
    "rootDir": "src",
    "declaration": true,
    "declarationMap": true
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}

Artıları: Her yerde çalışır (bundler varsayımı yok), önbelleğe alınabilir, exports ile açık API yüzeyi.

Eksileri: Build adımı gerekli, biraz daha fazla yapılandırma.

3. Yayınlanan Paket

Derlenmiş paketle aynı, ama ayrıca npm'e yayınlanır. Monorepo dışında kullanılması gereken kod için.

Paket İsimlendirme

npm registry çakışmalarını önlemek için bir ad alanı öneki kullan. @repo/ kullanılmayan, talep edilemeyen bir ad alanıdır — yayınlanmayacak iç paketler için ideal.

@repo/ui
@repo/utils
@repo/config-ts
@repo/config-eslint

İyi Bir Paket package.json'ının Anatomisi

{
  "name": "@repo/ui",
  "version": "0.0.0",
  "private": true,
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "default": "./dist/index.js"
    },
    "./button": {
      "types": "./dist/button.d.ts",
      "default": "./dist/button.js"
    }
  },
  "scripts": {
    "build": "tsc",
    "dev": "tsc --watch",
    "check-types": "tsc --noEmit",
    "lint": "eslint src/"
  },
  "peerDependencies": {
    "react": "^19.0.0"
  },
  "devDependencies": {
    "@repo/config-ts": "workspace:*",
    "@repo/config-eslint": "workspace:*",
    "typescript": "^5.0.0"
  }
}

İç Paket Kurulumu

// apps/web/package.json
{
  "dependencies": {
    "@repo/ui": "workspace:*",
    "@repo/utils": "workspace:*"
  }
}

workspace:*, "bu workspace'de hangi sürüm varsa onu kullan" anlamına gelir. Paket yöneticisi, indirmek yerine paketi sembolik olarak bağlar.

Paket Grafiği

Turborepo, dependencies'ten otomatik olarak bir Paket Grafiği oluşturur. Bu şunların temeli:

  • Bir bağımlılık değiştiğinde hangi paketlerin yeniden derleneceğini bilmek
  • Görevlerin topolojik sıralaması (^build = "önce tüm bağımlılıklarımı derle")
  • CI'da --affected filtreleme
apps/web → bağımlı → packages/ui → bağımlı → packages/utils

utils değişirse, Turborepo ui ve web'in yeniden derlenmesi gerektiğini bilir.


4. Görevleri Yapılandırma

turbo.json Anatomisi

// turbo.json (veya yorumlar için turbo.jsonc)
{
  "$schema": "https://turborepo.dev/schema.json",
  "tasks": {
    "build": {
      "dependsOn": ["^build"],      // önce tüm bağımlılıklarda build çalıştır
      "outputs": ["dist/**", ".next/**", "!.next/cache/**"]
    },
    "dev": {
      "cache": false,               // dev sunucularını asla önbelleğe alma
      "persistent": true            // uzun süreli işlem
    },
    "lint": {
      "dependsOn": ["^build"]       // tip import'ları için deplerden sonra lint
    },
    "check-types": {
      "dependsOn": ["^check-types"]
    },
    "test": {
      "dependsOn": ["^build"],
      "outputs": ["coverage/**"]
    },
    "test:watch": {
      "cache": false,
      "persistent": true
    }
  }
}

dependsOn Sözdizimi

"dependsOn": ["^build"]    → tüm bağımlılık paketlerinde build'i önce çalıştır (topolojik)
"dependsOn": ["build"]     → AYNI pakette build'i önce çalıştır
"dependsOn": []            → bağımlılık yok, her zaman çalıştır
"dependsOn": ["lint", "^build"] → bu paketin lint'ini VE tüm dep'lerin build'ini önce çalıştır

^ topolojik operatördür — "bağımlı olduğum tüm paketler." ^ olmadan "bu paket" anlamına gelir.

Görev Tipleri

{
  "tasks": {
    // ✅ Önbelleğe alınabilir build — önbelleğe alınacak çıktıları var
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**"]
    },
 
    // ✅ Önbelleğe alınabilir kontrol — dosya çıktısı yok, ama loglar önbelleğe alınır
    "check-types": {
      "dependsOn": ["^check-types"]
    },
 
    // ✅ Önbelleğe alınabilir lint
    "lint": {},
 
    // ❌ Önbelleğe alınamaz — her çalıştırmada farklı sonuç
    "dev": {
      "cache": false,
      "persistent": true
    },
 
    // ❌ Önbelleğe alınamaz — yan etkiler (DB mutasyonları, API çağrıları)
    "db:push": {
      "cache": false
    }
  }
}

Paket Yapılandırmaları

Özel görev yapılandırması gerektiren paketler için, o pakette bir turbo.json oluştur:

// apps/web/turbo.json
{
  "extends": ["//"],  // kökten miras al
  "tasks": {
    "build": {
      "outputs": [".next/**", "!.next/cache/**"]  // yalnızca Next.js çıktıları, dist/** değil
    }
  }
}
// apps/docs/turbo.json
{
  "extends": ["//"],
  "tasks": {
    "build": {
      "outputs": ["out/**"]  // statik export
    }
  }
}

Turborepo 2.7+'da diğer paketlerden de genişletebilirsin:

{
  "extends": ["//", "@repo/config-turbo"]
}

Yardımcı Görevler (Sidecar)

Diğer görevlerle birlikte çalışması gereken görevler için (dev veritabanı gibi):

{
  "tasks": {
    "dev": {
      "cache": false,
      "persistent": true,
      "with": ["db:start"]  // db:start'ı yardımcı görev olarak çalıştır
    },
    "db:start": {
      "cache": false,
      "persistent": true
    }
  }
}

5. Önbellekleme

Önbellekleme Nasıl Çalışır

Turborepo şunları hash'ler:

  • Paketteki kaynak dosyalar (varsayılan olarak gitignore edilmemiş tüm dosyalar)
  • Belirttiğin inputs glob kalıpları
  • env'de listelenen ortam değişkenleri
  • Global bağımlılıklar (globalDependencies)
  • Bağımlılık paketlerinden dependsOn çıktıları
  • Görev tanımının kendisi

Hash önbelleğe alınmış bir girişle eşleşirse: çıktıları geri yükle ve logları anında tekrar çal. Eşleşmezse: görevi çalıştır, ardından sonuçları önbelleğe al.

Yerel vs Uzak Önbellek

Yerel önbellek  → .turbo/cache (makine başına, geliştirici başına)
Uzak önbellek   → Vercel / kendi barındırma (ekip + CI genelinde paylaşılan)

Uzak önbellek, en büyük kazanımların geldiği yer — bir meslektaşının build'i senin önbellek isabeti.

Çıktıları Yapılandırma

Çıktıları her zaman bildur. Bildirmezsen, Turborepo onları geri yükleyemez:

{
  "tasks": {
    "build": {
      "outputs": [
        "dist/**",           // derlenmiş çıktı
        ".next/**",          // Next.js build
        "!.next/cache/**"    // Next.js dahili önbelleği hariç tut (çok büyük)
      ]
    },
    "check-types": {
      // çıktı yok — yalnızca loglar önbelleğe alınır
    },
    "test": {
      "outputs": ["coverage/**"]  // test kapsama raporu
    }
  }
}

Girdileri Yapılandırma

Turborepo varsayılan olarak paketteki tüm gitignore edilmemiş dosyaları girdi olarak kullanır. Daha hassas olmak için inputs ile geçersiz kıl:

{
  "tasks": {
    "check-types": {
      "inputs": ["src/**/*.ts", "src/**/*.tsx", "tsconfig.json"]
      // Yalnızca TypeScript dosyaları tip kontrolü hash'ini etkiler
      // README.md değişikliği önbellek isabetsizliğine yol açmaz
    },
    "lint": {
      "inputs": ["src/**/*.ts", "src/**/*.tsx", ".eslintrc.js"]
    },
    "test": {
      "inputs": ["src/**/*.ts", "src/**/*.tsx", "**/*.test.ts", "jest.config.js"]
    }
  }
}

Uzak Önbellek Kurulumu

Vercel (Vercel'e deploy edildiğinde sıfır yapılandırma):

# Giriş yap ve bağla
turbo login
turbo link

CI'da Vercel:

# CI ortam değişkenleri olarak ayarla
TURBO_TOKEN=vercel-token'in
TURBO_TEAM=ekip-slug'in

Kendi barındırma (ducktors/turborepo-remote-cache):

# CI ortam değişkenleri
TURBO_API=https://onbellek-sunucun.com
TURBO_TOKEN=gizli-token'in
TURBO_TEAM=ekibin

Yeni --cache flag'i (2.9'da kullanımdan kaldırılan flag'lerin yerini alır):

# Yerel okuma+yazma, uzak salt okunur
turbo build --cache=local:rw,remote:r
 
# Yalnızca uzak
turbo build --cache=remote:rw
 
# Önbelleği tamamen devre dışı bırak (--no-cache'in yerini alır)
turbo build --cache=local:r,remote:r

Önbellek Artifact İmzalama

Ek güvenlik için HMAC ile artifact'ları imzala:

// turbo.json
{
  "remoteCache": {
    "signature": true
  },
  "futureFlags": {
    "longerSignatureKey": true  // minimum 32 bayt anahtar zorla (3.0 varsayılanı)
  }
}
# Ortam değişkeni
TURBO_REMOTE_CACHE_SIGNATURE_KEY=minimum-32-bayt-gizli-anahtarin

Önbellek İsabetsizliklerini Hata Ayıklama

# Bir görevin neden önbelleği ıskaladığını gör
turbo build --summarize
# Hash girdilerini içeren .turbo/runs/*.json çıktısı verir
 
# Çalıştırmadan neyin çalışacağını gör
turbo build --dry-run
turbo build --dry-run=json | jq '.tasks[] | select(.cache.status == "MISS")'
 
# Önbelleği yoksayarak yeniden çalıştırmaya zorla (çalıştırmadan sonra önbelleğe yazar)
turbo build --force
 
# Neyin çalışacağını görselleştir
turbo build --graph
 
# OpenTelemetry (2.9+, deneysel)
# turbo.json: { "futureFlags": { "experimentalObservability": true } }
# OTLP backend'ine metrik gönderir

Ne Zaman Önbelleğe ALMAMALI

❌ Ağ yan etkileri olan görevler (API çağrıları, DB mutasyonları)
❌ Dev sunucuları (her zaman cache: false, persistent: true kullan)
❌ Önbellek ek yükünden daha hızlı görevler (100ms altı görevler)
❌ Devasa çıktıları olan görevler (>500MB Docker imajları)

6. Ortam Değişkenleri

Önbellek Sorunu

Ortam değişkenleri önbellek hash'inin bir parçasıdır. Bir env değişkeni değişirse, önbellek ıskalanır. Env değişkenlerini bildirmeyi unutursan, eski önbellekler elde edersin.

DATABASE_URL değişirse → build önbelleği ıskalasın (bundle'ı etkiler)
CI_JOB_ID değişirse    → build önbelleği ıskalamamalı (çıktıyla ilgisiz)

Ortam Değişkenlerini Bildirme

{
  "tasks": {
    "build": {
      "env": [
        "DATABASE_URL",        // build'i etkiler → dahil et
        "NEXT_PUBLIC_APP_URL", // public env, bundle'ı etkiler → dahil et
        "NODE_ENV"             // build davranışını etkiler → dahil et
      ],
      "passThroughEnv": [
        "CI",                  // çalışma zamanında gerekli, çıktıyı etkilemez → geçir
        "VERCEL_URL"           // deploy başına değişen URL → geçir
      ]
    }
  }
}

env: Bu değişkenlerdeki değişiklikler önbelleği geçersiz kılar. passThroughEnv: Göreve geçirilir ama önbellek hash'ini etkilemez.

Global Bağımlılıklar

TÜM görevleri etkileyen değişkenler ve dosyalar:

{
  "globalEnv": [
    "TURBO_TEAM",
    "NODE_ENV"
  ],
  "globalDependencies": [
    ".env",          // .env değişikliği tüm önbellekleri geçersiz kılar
    "tsconfig.json"  // kök tsconfig değişiklikleri her şeyi etkiler
  ]
}

Framework Otomatik Tespiti

Turborepo, bilinen framework'ler için public env değişkenlerini otomatik tespit eder:

Next.js → NEXT_PUBLIC_* otomatik olarak hash'e dahil edilir
Vite    → VITE_* otomatik olarak dahil edilir
CRA     → REACT_APP_* otomatik olarak dahil edilir

Bunları manuel olarak bildirmen gerekmez.

CI Env Değişkeni Sorunu

CI sistemleri her çalıştırmada değişen CI_JOB_ID, GITHUB_SHA, BUILD_NUMBER gibi değişkenler ayarlar. Bunları hash'e dahil edersen, hiçbir zaman önbelleğe isabet edemezsin.

Otomatik çıkarımdan CI'ya özel önekleri hariç tutmak için TURBO_CI_VENDOR_ENV_KEY kullan:

# GITHUB_*'ı Turborepo'nun otomatik env çıkarımından hariç tut
TURBO_CI_VENDOR_ENV_KEY=GITHUB_

ESLint / Biome Kuralı

Turborepo 2.7+, bildirilmemiş env değişkenlerini yakalayan bir Biome kuralı sağlar:

// biome.json
{
  "linter": {
    "rules": {
      "nursery": {
        "noUndeclaredEnvVars": "warn"  // turbo.json'ı otomatik okur
      }
    }
  }
}

ESLint için:

bun add -D eslint-plugin-turbo
// eslint.config.mjs
import turboPlugin from 'eslint-plugin-turbo'
 
export default [
  {
    plugins: { turbo: turboPlugin },
    rules: {
      'turbo/no-undeclared-env-vars': 'error',
    },
  },
]

7. Geliştirme İş Akışı

Görevleri Çalıştırma

# Tüm paketlerde görev çalıştır
turbo build
turbo dev
turbo lint
 
# Yalnızca belirli paketler için çalıştır
turbo build --filter=web
turbo build --filter=@repo/ui
turbo build --filter=./apps/web
 
# Bir paket ve tüm bağımlılıkları için çalıştır
turbo build --filter=web...
 
# Main'e göre değişen paketler için çalıştır
turbo build --affected
 
# Bir dizindeki paketler için çalıştır
turbo build --filter="./apps/*"

İzleme Modu

# Dosyalar değiştiğinde görevleri yeniden çalıştır
turbo watch build       # kaynaklar değiştiğinde yeniden derle
turbo watch check-types # kaydedince yeniden tip kontrolü yap

İzleme modu, yalnızca dosyaların değiştiği paketlerdeki görevleri yeniden çalıştırır.

Terminal Arayüzü (TUI)

Turborepo 2.0+, etkileşimli bir TUI ile gelir:

turbo dev  # otomatik olarak TUI kullanır
 
# Belirli UI'yı zorla
turbo build --ui=tui     # etkileşimli
turbo build --ui=stream  # geleneksel log akışı (CI için iyi)

TUI'de: paketler arasında gezinmek için ok tuşlarını kullan, paketin loglarına odaklanmak için Enter'a bas, odaktan çıkmak için Ctrl+Z.

turbo query (2.9'da Kararlı)

GraphQL veya kısayollarla monorepo yapını sorgula:

# Etkileşimli GraphiQL playground'u aç
turbo query
 
# Mevcut değişikliklerden etkilenen paketler hangileri?
turbo query affected
 
# packages/ui'yi değiştirirsem hangi paketler etkilenir?
turbo query affected --packages
 
# packages/ui'yi değiştirirsem hangi görevler çalışır?
turbo query affected --tasks build
 
# Tüm paketleri listele
turbo query ls
 
# Belirli bir paket için detaylar
turbo query ls web
 
# Yalnızca etkilenen paketleri listele
turbo query ls --affected

Devtools

# Görsel paket/görev grafiği gezginini başlat
turbo devtools

Paket Grafiğini (neyin neye bağımlı olduğunu) ve Görev Grafiğini (ne zaman ne çalışır) görselleştir. Yapılandırmayı değiştirdikçe canlı yenilenir.

Yükseltme

# Codemod ile otomatik yükseltme
bunx @turbo/codemod migrate

Breaking change migration'larını otomatik uygular. turbo sürümünü artırdığında her seferinde çalıştır.


8. CI/CD

GitHub Actions — Temel Kurulum

# .github/workflows/ci.yml
name: CI
 
on:
  push:
    branches: ["main"]
  pull_request:
    types: [opened, synchronize]
 
jobs:
  build-and-test:
    name: Build ve Test
    runs-on: ubuntu-latest
    timeout-minutes: 15
 
    env:
      # Vercel Uzak Önbellek
      TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
      TURBO_TEAM: ${{ vars.TURBO_TEAM }}
 
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 2  # --affected karşılaştırması için gerekli
 
      - uses: pnpm/action-setup@v4
        with:
          version: 9
 
      - name: Node.js'i Kur
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: "pnpm"
 
      - name: Bağımlılıkları Kur
        run: pnpm install --frozen-lockfile
 
      - name: Lint + Tip Kontrolü
        run: pnpm turbo lint check-types
 
      - name: Test
        run: pnpm turbo test
 
      - name: Build
        run: pnpm turbo build

Yalnızca Etkilenen CI

Yalnızca PR'da değişen paketler için görevleri çalıştır:

- name: Etkilenen görevleri çalıştır
  run: pnpm turbo build test --affected
  # Turborepo, GitHub Actions'ta GITHUB_BASE_REF'i otomatik tespit eder
  # PR head'ini PR base branch'iyle karşılaştırır
  # Geçmiş mevcut değilse (shallow clone) her şeyi çalıştırmaya geri döner

Önemli: --affected git geçmişine ihtiyaç duyar. Tam geçmiş için fetch-depth: 0 kullan:

- name: Checkout
  uses: actions/checkout@v4
  with:
    fetch-depth: 0  # doğru --affected için tam geçmiş

CI'da Yapılandırılmış Loglar (2.9+)

- name: Yapılandırılmış loglarla build
  run: pnpm turbo build --log-file=.turbo/build-log.json
 
- name: Build logunu yükle
  uses: actions/upload-artifact@v4
  if: always()
  with:
    name: build-log
    path: .turbo/build-log.json

Kendi Barındırmalı Uzak Önbellek (GitHub Actions Cache Yedek)

Vercel Uzak Önbelleğin yoksa, yedek olarak GitHub Actions önbelleğini kullan:

- name: Turbo build kurulumunu önbelleğe al
  uses: actions/cache@v4
  with:
    path: .turbo
    key: ${{ runner.os }}-turbo-${{ github.sha }}
    restore-keys: |
      ${{ runner.os }}-turbo-

Not: Bu makine başına önbellek, paylaşılan bir uzak önbellekten çok daha az etkilidir. Ekip genelinde paylaşım için Vercel Uzak Önbelleği veya kendi barındırmalı sunucu kullan.

CI Stratejisi: Hepsini Lint/Test Et, Etkilenenleri Build Et

jobs:
  kalite:
    name: Lint + Tipler + Test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with: { fetch-depth: 0 }
      - run: pnpm install --frozen-lockfile
      # Kalite kontrollerini her şeyde çalıştır — uzak önbellek gerisini halleder
      - run: pnpm turbo lint check-types test
 
  deploy:
    name: Build ve Deploy
    runs-on: ubuntu-latest
    needs: kalite
    steps:
      - uses: actions/checkout@v4
        with: { fetch-depth: 0 }
      - run: pnpm install --frozen-lockfile
      # Yalnızca değişen uygulamaları + bağımlılıklarını build et
      - run: pnpm turbo build --affected

Turborepo Prune ile Docker

turbo prune, tek bir uygulama için yalnızca neye ihtiyacı varsa onu içeren seyrek bir workspace oluşturur:

# web uygulaması için kırpılmış workspace oluştur
turbo prune web --docker

Çıktı:

out/
├── json/          # yalnızca package.json dosyaları (bağımlılık kurulum katmanı için)
│   ├── package.json
│   └── apps/web/package.json
└── full/          # tam kaynak kodu
    ├── package.json
    ├── turbo.json
    └── apps/web/
FROM node:20-alpine AS base
 
# Kırpılmış workspace'den bağımlılıkları kur
FROM base AS installer
WORKDIR /app
COPY out/json/ .
RUN pnpm install --frozen-lockfile
 
# Tam kaynaktan build et
FROM base AS builder
WORKDIR /app
COPY --from=installer /app/node_modules ./node_modules
COPY out/full/ .
 
# Uzak önbellek kimlik bilgileri
ARG TURBO_TOKEN
ARG TURBO_TEAM
ENV TURBO_TOKEN=$TURBO_TOKEN
ENV TURBO_TEAM=$TURBO_TEAM
 
RUN pnpm turbo build --filter=web
 
# Üretim imajı
FROM base AS runner
WORKDIR /app
COPY --from=builder /app/apps/web/.next/standalone ./
EXPOSE 3000
CMD ["node", "server.js"]

9. Paylaşılan Yapılandırma Paketleri

Monoreponun en yüksek kaldıraç noktası: yapılandırmayı bir kez yaz, her yerde paylaş.

TypeScript Yapılandırması

packages/
└── config-ts/
    ├── package.json
    ├── base.json
    ├── nextjs.json
    └── react-library.json
// packages/config-ts/package.json
{
  "name": "@repo/config-ts",
  "version": "0.0.0",
  "private": true,
  "exports": {
    "./base": "./base.json",
    "./nextjs": "./nextjs.json",
    "./react-library": "./react-library.json"
  }
}
// packages/config-ts/base.json
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "strict": true,
    "skipLibCheck": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true
  }
}
// packages/config-ts/nextjs.json
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "extends": "./base.json",
  "compilerOptions": {
    "plugins": [{ "name": "next" }],
    "jsx": "preserve",
    "allowJs": true,
    "incremental": true,
    "noEmit": true
  }
}
// packages/config-ts/react-library.json
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "extends": "./base.json",
  "compilerOptions": {
    "jsx": "react-jsx",
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true
  }
}

Bir Next.js uygulamasında kullanım:

// apps/web/tsconfig.json
{
  "extends": "@repo/config-ts/nextjs",
  "compilerOptions": {
    "baseUrl": ".",
    "paths": { "@/*": ["./src/*"] }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules"]
}

ESLint Yapılandırması

packages/
└── config-eslint/
    ├── package.json
    ├── base.js         # paylaşılan kurallar
    ├── next.js         # Next.js'e özgü
    └── react-internal.js # iç paketler için
// packages/config-eslint/base.js
import js from "@eslint/js"
import turboPlugin from "eslint-plugin-turbo"
import tsPlugin from "@typescript-eslint/eslint-plugin"
import tsParser from "@typescript-eslint/parser"
 
export default [
  js.configs.recommended,
  {
    plugins: {
      turbo: turboPlugin,
      "@typescript-eslint": tsPlugin,
    },
    languageOptions: {
      parser: tsParser,
    },
    rules: {
      "turbo/no-undeclared-env-vars": "error",
      "@typescript-eslint/no-unused-vars": "error",
      "@typescript-eslint/no-explicit-any": "warn",
    },
  },
]
// apps/web/eslint.config.mjs
import baseConfig from "@repo/config-eslint/next"
 
export default [...baseConfig]

Prettier Yapılandırması

// packages/config-prettier/package.json
{
  "name": "@repo/config-prettier",
  "version": "0.0.0",
  "private": true,
  "main": "index.json"
}
// packages/config-prettier/index.json
{
  "semi": false,
  "singleQuote": true,
  "tabWidth": 2,
  "trailingComma": "es5",
  "printWidth": 100
}
// apps/web/package.json
{
  "prettier": "@repo/config-prettier"
}

10. Deploy Stratejileri

Bağımsız Uygulama Deployları

Her uygulama, kendi paketi veya bağımlılıkları değiştiğinde bağımsız olarak deploy edilir:

# .github/workflows/deploy-web.yml
name: Web Deploy
 
on:
  push:
    branches: [main]
 
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with: { fetch-depth: 0 }
 
      - run: pnpm install --frozen-lockfile
 
      # Yalnızca web veya bağımlılıkları değiştiyse deploy et
      - name: Web'in etkilenip etkilenmediğini kontrol et
        id: etkilenen
        run: |
          ETKILENEN=$(pnpm turbo query affected --packages | grep '"web"' || true)
          echo "deploy=$([[ -n "$ETKILENEN" ]] && echo 'true' || echo 'false')" >> $GITHUB_OUTPUT
 
      - name: Web'i build et
        if: steps.etkilenen.outputs.deploy == 'true'
        run: pnpm turbo build --filter=web
 
      - name: Vercel'e deploy et
        if: steps.etkilenen.outputs.deploy == 'true'
        run: vercel deploy --prod
        env:
          VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}

Vercel Monorepo Deploy

Vercel, Turborepo'yu yerel olarak anlar. Her proje için Vercel'de Kök Dizini ayarla:

Proje: web  → Kök Dizin: apps/web
Proje: docs → Kök Dizin: apps/docs
Proje: api  → Kök Dizin: apps/api

Vercel, aynı ekipteki tüm projeler için sıfır yapılandırmayla otomatik olarak Turborepo Uzak Önbelleğini kullanır.

Koşullu Docker Build

- name: Docker imajı build et ve push et
  run: |
    # Yalnızca api değiştiyse build et
    if pnpm turbo query affected --packages | grep -q '"api"'; then
      docker build -f apps/api/Dockerfile \
        --build-arg TURBO_TOKEN=${{ secrets.TURBO_TOKEN }} \
        --build-arg TURBO_TEAM=${{ vars.TURBO_TEAM }} \
        -t benim-api:${{ github.sha }} .
      docker push benim-api:${{ github.sha }}
    fi

11. Araç Referansı

turbo.json Anahtar Referansı

{
  "$schema": "https://turborepo.dev/schema.json",
 
  // Global ayarlar
  "globalDependencies": [".env", "tsconfig.json"],
  "globalEnv": ["NODE_ENV", "DATABASE_URL"],
  "globalPassThroughEnv": ["CI", "GITHUB_SHA"],
 
  // Görev tanımları
  "tasks": {
    "build": {
      "dependsOn": ["^build"],      // topolojik: tüm dep'lerde önce çalıştır
      "outputs": ["dist/**"],        // önbelleğe alınacak dosyalar
      "inputs": ["src/**"],          // hash'i etkileyen dosyalar (varsayılan: tümü)
      "env": ["BENIM_DEGISKENIM"],   // hash'i etkileyen env değişkenleri
      "passThroughEnv": ["CI"],      // geçirilen ama hash'lenmeyen env değişkenleri
      "cache": true,                 // varsayılan: true
      "outputLogs": "full"           // full | hash-only | new-only | errors-only | none
    },
    "dev": {
      "cache": false,
      "persistent": true,            // uzun süreli işlem
      "with": ["db:start"]           // yardımcı görevler
    }
  },
 
  // Uzak önbellek
  "remoteCache": {
    "signature": true
  },
 
  // UI
  "ui": "tui",                       // tui | stream
 
  // 3.0 geçişi için Future Flags
  "futureFlags": {
    "globalConfiguration": true,
    "affectedUsingTaskInputs": true,
    "watchUsingTaskInputs": true,
    "longerSignatureKey": true,
    "experimentalObservability": true
  },
 
  // OpenTelemetry (deneysel, futureFlag ile geçilir)
  "experimentalObservability": {
    "otel": {
      "enabled": true,
      "endpoint": "http://otel-collector.ornek.com:4317",
      "protocol": "grpc"
    }
  }
}

CLI Referansı

# Görev çalıştır
turbo <görev>                      # tüm paketlerde görev çalıştır
turbo <görev> --filter=<paket>     # belirli pakette çalıştır
turbo <görev> --affected           # yalnızca değişen paketlerde çalıştır
turbo <görev> --force              # yeniden çalıştırmayı zorla, önbelleği yoksay
turbo <görev> --dry-run            # neyin çalışacağını gör
turbo <görev> --dry-run=json       # makine okunabilir kuru çalıştırma
turbo <görev> --graph              # görev grafiği çıktısı
turbo <görev> --summarize          # hash detaylarıyla çalıştırma özeti
turbo <görev> --json               # NDJSON logları akıt (2.9+)
turbo <görev> --log-file=yol.json  # yapılandırılmış logları dosyaya yaz (2.9+)
 
# Önbellek kontrolü (2.9+, kullanımdan kaldırılan flag'lerin yerini alır)
turbo build --cache=local:rw,remote:r   # yerel okuma+yazma, uzak salt okunur
turbo build --cache=remote:rw           # yalnızca uzak
turbo build --cache=local:r,remote:r    # salt okunur (önbelleğe yazma yok)
 
# Sorgu (2.9'da kararlı)
turbo query                       # GraphiQL playground'u aç
turbo query affected               # etkilenen görevleri göster
turbo query affected --packages    # etkilenen paketleri göster
turbo query affected --tasks build # etkilenen build görevleri
turbo query ls                     # tüm paketleri listele
turbo query ls web                 # web paketi için detaylar
turbo query ls --affected          # etkilenen paketleri listele
 
# Uzak önbellek
turbo login                        # Vercel ile kimlik doğrula
turbo link                         # Vercel Uzak Önbelleğine bağla
turbo logout
 
# Devtools
turbo devtools                     # görsel grafik gezginini aç
 
# Yükseltme
bunx @turbo/codemod migrate        # codemod ile otomatik yükseltme

Filtre Sözdizimi

# İsme göre
--filter=web
--filter=@repo/ui
 
# Yola göre
--filter=./apps/web
--filter="./apps/*"
 
# Bağımlıları dahil et (hedefe bağımlı paketler)
--filter=web...          # web ve bağımlıları
--filter=...web          # web ve bağımlılıkları
 
# Git değişikliklerine göre
--filter="[HEAD^1]"      # son commit'te değişen
--filter="[main...HEAD]" # main'den itibaren değişen
 
# Etkilenen (akıllı git tespiti)
--affected               # base ref'i otomatik tespit eder

Kaçınılacak Kullanımdan Kaldırılan Özellikler (3.0 Hazırlığı)

# Kullanımdan kaldırılan → Yerine
turbo-ignore                  → turbo query affected
turbo scan                    → geçersiz
--parallel                    → turbo.json'da persistent + with kullan
--no-cache                    → --cache=local:r,remote:r
--remote-only                 → --cache=remote:rw
TURBO_REMOTE_ONLY             → --cache=remote:rw
TURBO_REMOTE_CACHE_READ_ONLY  → --cache=local:rw,remote:r

Benim create-turbo-stack Şablonum

Açık kaynak scaffold CLI'm, bu kurulumla önceden yapılandırılmış Turborepo monorepoları üretir:

bunx create-turbo-stack

Üretir:

  • apps/web — Next.js 16 + Tailwind CSS
  • packages/ui — JIT React bileşenleri
  • packages/config-ts — Paylaşılan TypeScript yapılandırması
  • packages/config-eslint — Paylaşılan ESLint yapılandırması
  • build, dev, lint, check-types, test ile önceden yapılandırılmış turbo.json
  • Uzak Önbellek içeren GitHub Actions CI iş akışı
  • pnpm veya Bun workspace desteği

Ek: Hızlı Referans

Repository Kontrol Listesi

Yapı
  ☐ Deploy edilebilir uygulamalar için apps/
  ☐ Paylaşılan kütüphaneler ve yapılandırma için packages/
  ☐ Kök package.json'da packageManager alanı
  ☐ .gitignore'da .turbo
  ☐ İç paketler için ad alanı öneki (@repo/)

Görevler
  ☐ Kütüphaneler için build'de dependsOn: ["^build"] var
  ☐ build çıktıları bildiriliyor
  ☐ dev'de cache: false, persistent: true var
  ☐ Her TypeScript paketinde check-types görevi
  ☐ Uygulamaya özgü çıktılar için Paket Yapılandırmaları (paket başına turbo.json)

Önbellekleme
  ☐ Env değişkenleri tasks.env'de bildiriliyor
  ☐ CI env değişkenleri önbellek isabetsizliğine neden olmuyor
  ☐ Ekip için uzak önbellek yapılandırılmış
  ☐ Önbellek artifact imzalama etkin (üretim)

CI
  ☐ --affected'ın çalışması için fetch-depth: 0
  ☐ TURBO_TOKEN ve TURBO_TEAM CI secret'ları olarak ayarlanmış
  ☐ Seçici build'ler için --affected
  ☐ CI dostu çıktı için --ui=stream

Yaygın Önbellek İsabetsizlik Nedenleri

1. Env değişkeni turbo.json'da bildirilmemiş → env[]'e ekle
2. CI env değişkeni hash'e dahil → passThroughEnv[]'e ekle veya TURBO_CI_VENDOR_ENV_KEY ile hariç tut
3. outputs bildirilmemiş → outputs[]'a ekle
4. globalDependencies değişti (lockfile, tsconfig) → beklenen
5. Bağımlılık paketi değişti → beklenen (topolojik yayılım)

Son güncelleme: Nisan 2026. Turborepo 2.9 (Mart 2026) kapsar. Önemli özellikler: İlk Göreve Kadar Sürede %96 iyileştirme, turbo query kararlı, turbo.jsonc, OpenTelemetry (deneysel), yapılandırılmış loglama, 3.0 geçişi için Future Flags.