ViraStack
  • Akademi
  • Hakkında
  • Destek
Genel BakışKaynaklarKatkı
ViraStack

Frontend geliştiricileri için DX odaklı araç seti: starter’lar, ajan kuralları, form hook’ları ve rehber.

Ürünler

  • ViraStack Start
  • ViraStack AI
  • ViraStack Mask
  • ViraStack Password
  • ViraStack Guide

Keşfet

  • Akademi
  • Hakkında
  • Marka
  • Destek

© 2026 ViraStack.

Açık kaynak · MIT

Mimari ve Ölçeklenebilirlik

04 / 09

Monorepo

pnpm workspace ve Turborepo ile paylaşılan paketler ve ortak UI kütüphanesi.

Monorepo, birden fazla uygulama ve paketin tek bir repoda durmasıdır. Ortak UI bileşenlerini, TypeScript ayarlarını ve tipleri ayrı bir repoya bölmeden paylaşırsınız. Takımlar arası koordinasyon maliyeti düşer, paketi ve onu kullanan uygulamaları tek bir değişiklikte güncelleyebilirsiniz.1 Bu rehber frontend'de en yaygın ikiliyi kuruyor: paketleri birbirine bağlayan pnpm workspace ve görevleri sıralayıp önbelleğe alan Turborepo.

Ne zaman monorepo?

Monorepo mantıklıAyrı repo mantıklı
Birlikte evrilen uygulamalar ve ortak UI, tip, config paketleri var2Projeler birbirinden bağımsız ürünler2
Ortak kodu npm'e yayınlamadan paylaşmak istiyorsunuzKatı izolasyon gerekiyor2
Bir değişikliğin paketi ve tüm tüketicilerini tek PR'da güncellemesini istiyorsunuzEkipte CI olgunluğu yok2

Geçişin zor kısmı çoğu zaman teknik değil, organizasyonel: ekiplerin aynı repoda çalışmayı kabul etmesi gerekiyor.1

En uç örnek Google: on binlerce geliştirici için tek bir ortak kaynak gerçeği olarak devasa bir tek repo kullanıyor. Communications of the ACM'deki makale, bu modelin avantajlarını ve ödünleşimlerini, onu mümkün kılan sistemler ve iş akışlarıyla birlikte anlatıyor.3 Ödünleşimin frontend'deki karşılığı boyut: kod büyüdükçe build, test ve sürüm kontrolü yavaşlar, editör ağırlaşır.4 2026 tarihli bağımsız bir derleme kabaca şu ölçüyü veriyor: üç veya daha fazla deploy edilebilir uygulama, birkaç paylaşılan paket ve kod tabanında çalışan birden fazla ekip varsa monorepo mantıklı. Tek uygulama ve yaklaşık 10 kişiden küçük ekipler için erken.5 Fireship'in deyimiyle monorepo "blogunuz için abartı olabilir".4

Takımların bağımsız yayın döngüsü istediği durumlar için Micro Frontend rehberine bakın.

İki araç, iki iş

pnpm workspaceTurborepo
İşiPaketleri keşfeder, birbirine bağlar, tek lockfile tutar6Görevleri sıralar, paralel çalıştırır, sonuçları önbelleğe alır78
Ayar dosyasıpnpm-workspace.yamlturbo.json

Turborepo paket yöneticisinin workspace özelliğinin üzerine kuruludur.9 Bağımlılıkları indirmek, symlink'lemek ve çözümlemek yine paket yöneticisinin işidir.10 Aynı işi yapan bir alternatif Nx: mimari sınırları zorlayan mekanizmalar da sunuyor.11 Fireship'in karşılaştırması farkı iyi özetliyor: ikisi de bağımlılık grafiği çıkarır, çıktıları önbelleğe alır ve işleri paralel çalıştırır. Nx daha eski ve geniş (kod üretimi, eklentiler, dağıtık görev çalıştırma), Turborepo daha yeni ve minimal, mevcut workspace'e kolayca eklenir.4 (Video 2021 tarihli, araç ayrıntıları değişti, kavramlar geçerli.) 2026 itibarıyla pnpm workspaces yeni monorepo'lar için varsayılan sayılıyor.5

Yapı

repo/
├── apps/
│   ├── web/                  # Next.js uygulaması
│   └── admin/                # ikinci uygulama
├── packages/
│   ├── ui/                   # @repo/ui
│   ├── typescript-config/    # @repo/typescript-config
│   └── eslint-config/        # @repo/eslint-config
├── package.json
├── pnpm-workspace.yaml
└── turbo.json

Turborepo dokümanı uygulama ve servisleri apps/ altında, kütüphane ve araçları packages/ altında toplamayı öneriyor.9 Anthony Shew'un videosunda da aynı iskelet var: workspace'ler apps ve packages altındaki parçaları tek grafikte bağlıyor, her paketin kendi package.json dosyası, dışa açtığı API için exports alanı ve kendi scripts alanı oluyor.12

# pnpm-workspace.yaml
packages:
  - "apps/*"
  - "packages/*"
// package.json (kök)
{
  "private": true,
  "scripts": {
    "build": "turbo run build",
    "dev": "turbo run dev",
    "lint": "turbo run lint"
  },
  "devDependencies": {
    "turbo": "latest"
  }
}
  • apps/* ve packages/* altında package.json olan her klasör bir pakettir. İç içe paketler (apps/a ve apps/a/b) desteklenmez.9

  • Lockfile şart. Turborepo iç paketler arasındaki bağımlılıkları buradan anlıyor.9

  • Kök dizine yalnızca depo yönetim araçları konur (turbo, husky, lint-staged). Uygulama bağımlılıkları, onları kullanan pakete yazılır.10 Tally Barak'ın DevOps.js konuşmasındaki uyarıya göre kökte toplanan (hoisted) bağımlılıklar eksik bildirimleri gizleyebilir ve hata ancak deploy'da ortaya çıkar.13

Paylaşılan paketler

Bir uygulama, iç paketi npm'deki bir paket gibi ekler. Sürüm yerine paket yöneticisinin workspace sözdizimini yazarsınız:14

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

workspace: protokolünde pnpm yerel workspace paketi dışında hiçbir şeye çözümlemeyi reddeder. Yanlışlıkla registry'den başka bir sürüm inmez.6 Paket adında kapsamlı bir önek kullanın. Turborepo dokümanı @repo kullanıyor, çünkü npm'de alınamayan bir ad alanı.9

Aynı bağımlılığı birçok paket kullanıyorsa sürümü tek yerde tutmak için pnpm catalogs kullanabilirsiniz (pnpm 9.5 ve sonrası):10

# pnpm-workspace.yaml
packages:
  - "apps/*"
  - "packages/*"

catalog:
  react: ^19.0.0
  react-dom: ^19.0.0
// apps/web/package.json ve packages/ui/package.json
{
  "dependencies": {
    "react": "catalog:",
    "react-dom": "catalog:"
  }
}

Catalogs üç şey kazandırır: workspace'te her bağımlılığın tek sürümü olur, güncelleme yalnızca pnpm-workspace.yaml'da tek satırlık değişikliktir ve package.json dosyalarında merge çakışması çıkmaz.15

Paketleri tasarlarken iki kural işinizi görür:

  • Her pakete tek amaç: @repo/ui tüm paylaşılan UI bileşenlerini, @repo/typescript-config TypeScript ayarlarını barındırır.16

  • Uygulamalar paylaşılan kod barındırmaz. Ortak kodu ayrı bir pakete koyun, uygulamalar o pakete bağlansın. Uygulamalar paket grafiğinin sonudur.16

Ortak UI paketi

Bir iç paketi derlemenin iki yolu var:14

Just-in-TimeCompiled
Nasıl çalışırTypeScript dosyalarını doğrudan export eder, uygulamanın bundler'ı derlertsc ile dist klasörüne derlenir
YapılandırmaÇok azDaha fazla
Turborepo önbelleğiPaketin kendi build adımı olmadığı için önbelleğe alınamazBuild çıktıları outputs ile önbelleğe alınır
Ne zamanUygulamalar Turbopack, webpack veya Vite gibi modern bir bundler kullanıyorsaPaketi TypeScript'i derleyemeyen bir araç da kullanıyorsa

Next.js ve Vite uygulamalarının paylaştığı bir UI paketi için Just-in-Time en az yapılandırmayla başlayan seçenek. Uygulamaların build süresinden memnunsanız önbellek kaybı sorun olmaz.14

// packages/ui/package.json
{
  "name": "@repo/ui",
  "exports": {
    "./button": "./src/button.tsx",
    "./card": "./src/card.tsx"
  },
  "scripts": {
    "lint": "eslint . --max-warnings 0",
    "check-types": "tsc --noEmit"
  }
}
import { Button } from "@repo/ui/button"

Dosya başına exports tanımlamak, paketi tek bir barrel dosyasına bağlamaktan kaçınmanızı sağlar. Barrel dosyaları derleyiciler ve bundler'lar için zordur.9 Önceki rehberdeki index.ts tartışmasının paket düzeyindeki karşılığı bu.

Uyarı

Just-in-Time paketin içinde paths kullanamazsınız. Paketi tüketici derlediği için TypeScript'in compilerOptions.paths ayarı çalışmaz. Bunun yerine Node.js subpath imports kullanın: package.json içinde "imports": { "#*": "./src/*" } yazıp kodda #utils.ts gibi import edin.17 Uygulamanın kendi içinde @/ alias'ını kullanmaya devam edersiniz.

TypeScript ayarını da paylaşın. packages/typescript-config altında base.json ve nextjs.json, react-library.json gibi varyantlar durur, her paket kendi tsconfig.json'ında extends ile bunlardan birini seçer:17

// apps/web/tsconfig.json
{
  "extends": "@repo/typescript-config/nextjs.json",
  "include": ["src"],
  "exclude": ["node_modules"]
}

Kök dizinde tsconfig.json'a genellikle ihtiyacınız yok. Kökteki bir değişiklik tüm görevlerin önbelleğini düşürür.17

shadcn/ui kullanıyorsanız CLI monorepo'yu tanıyor. pnpm dlx shadcn@latest init --monorepo iki workspace (web ve ui) ve Turborepo kurar. apps/web içinde add button çalıştırdığınızda bileşen packages/ui altına iner ve import yolları güncellenir. Bileşenler @workspace/ui/components/button gibi import edilir.18 Her workspace'te bir components.json bulunmalı, style, iconLibrary ve baseColor ikisinde de aynı olmalı. Tailwind CSS v4'te components.json içindeki tailwind.config alanı boş bırakılır.18 shadcn paketi @workspace/ui adıyla kuruyor, bu rehberdeki @repo/ui ile aynı rolde: shadcn kullanıyorsanız onun adını koruyun.

turbo.json: görevler ve önbellek

// turbo.json
{
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": [".next/**", "!.next/cache/**", "!.next/dev/**", "dist/**"]
    },
    "lint": {
      "dependsOn": ["^lint"]
    },
    "check-types": {
      "dependsOn": ["^check-types"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    }
  }
}

Her tasks anahtarı, paketlerin package.json dosyasındaki aynı adlı script'i çalıştırır.7

  • ^build: Bir paketten önce bağımlılıklarının build görevini çalıştırır. @repo/ui derlenip bittikten sonra web derlenir.7

  • outputs: Hangi dosyaların önbelleğe alınacağını söyler. Yazmazsanız Turborepo dosyaları önbelleğe almaz ve önbellekten dönen çalıştırma dosyaları geri getirmez.78

  • dev: Hiç bitmeyen bir görev olduğu için persistent: true ve cache: false alır.7

Uyarı

"build": {} yazmak yetmez: görevler sırasız paralel çalışır ve çıktılar önbelleğe alınmaz, bu hızla hataya yol açar.7

Önbellek girdilerin parmak izine dayanır. Aynı parmak izi yeniden gelirse Turborepo işi yeniden yapmaz, sonucu önbellekten geri getirir.8 Yerel önbellek .turbo/cache klasöründe durur. npx turbo login ve npx turbo link ile Remote Cache'i açarsanız takım arkadaşlarınız ve CI aynı önbelleği paylaşır.8 Kök package.json'daki bir bağımlılığı güncellemek tüm görevlerin önbelleğini düşürür, kök dizini ince tutmanın pratik gerekçesi bu.8

check-types için ^check-types doğru önbellek davranışı verir ama görevleri paralel çalıştırmaz. Hem doğruluk hem paralellik için Turborepo dokümanı Transit Node kalıbını öneriyor.7

Görevleri çalıştırma

turbo run build                 # tüm paketler
turbo run build --filter=web... # web ve bağımlılıkları
turbo run build --filter=...ui  # ui ve onu kullanan paketler
turbo run build test lint       # birden çok görev, mümkün olduğunca paralel

... sonda bağımlılıkları, başta bağımlıları (dependents) kapsar.19 Bir paketi değiştirirken --filter=...ui ile onu kullanan her şeyin hâlâ derlendiğini görebilirsiniz.19

Uyarı

turbo komutlarını yalnızca kökteki package.json'a yazın. Paketlerin kendi script'lerine yazarsanız turbo kendini özyinelemeli çağırır.19

İpucu

Bir paketten başka bir pakete ulaşmak için ../ yazdığınızı fark ederseniz durun. O paketi bağımlılık olarak ekleyip adıyla import edin.9 Shew de modüllere dosya yoluyla değil paket adıyla erişilmesini monorepo düzeninin korunması için kritik görüyor.12

CI ve Docker

Önbelleğin asıl değeri CI'da ortaya çıkıyor. Michael Guay'in videosunda pnpm ve Turborepo ile bir Next.js ön yüzü ile NestJS arka yüzü tek workspace'te kuruluyor. TypeScript ve ESLint ayarları ile DTO tipleri paylaşılan paketlerde duruyor. GitHub Actions hattında Vercel Remote Cache bağlanınca daha önce derlenmiş çıktılar yeniden derlenmeden önbellekten geliyor.20 Shew'nun videosunda da aynı etki var: Remote Cache ile CI/CD'deki dağıtım süreçleri saniyelere iniyor.12 Turborepo'nun Docker rehberine göre kimlik bilgileri (TURBO_TEAM, TURBO_TOKEN) build argümanı olarak verilir. Yalnızca derleme aşamasında kullanıldıkları için son imaja girmezler.21

Monorepo'da bir uygulamayı Docker'a koyarken sorun şu: bir uygulamanın kilit dosyasındaki ilgisiz bir değişiklik, başka bir uygulamanın Docker build'ini gereksiz yere geçersiz kılabilir.21 turbo prune, hedef uygulamanın ihtiyaç duyduğu workspace'leri ve budanmış bir kilit dosyasını içeren küçük bir kopya üretir:21

turbo prune web --docker

--docker bayrağı çıktıyı ikiye böler: out/json yalnızca package.json dosyalarını (az değişir, bağımlılık kurulumu için), out/full ise kaynak kodu içerir. Budanmış kilit dosyası out/ kökünde durur.22 Çok aşamalı bir Dockerfile'da önce json ve kilit dosyasıyla bağımlılıkları kurar, sonra full ile derlersiniz. Böylece bağımlılıklar değişmedikçe kurulum katmanı önbellekte kalır.21 Tam Dockerfile için Turborepo'nun Docker rehberine bakın.

Kendin dene

  1. pnpm dlx create-turbo@latest ile örnek bir repo oluşturun. apps/web ile packages/ui arasındaki workspace:* bağını inceleyin.

  2. turbo run build komutunu iki kez çalıştırın. İkincisinde önbellekten dönen sonucu görün.

  3. packages/ui içinde bir bileşeni değiştirin ve turbo run build --filter=...ui çalıştırın. Hangi paketlerin yeniden derlendiğine bakın.

  4. turbo.json'dan outputs'u silip tekrar deneyin. Önbellekten dönen build'in dosyaları geri getirmediğini görün.

  5. Fireship'in Monorepos: Turborepo vs Nx videosunu (9 dk) izleyin. Ardından Tally Barak'ın 1001 Packages konuşmasından (24 dk) sürümleme ve bağımlılık kurulumu bölümlerine bakın.13 Daha sohbet havasında bir giriş için Syntax'ın monorepo bölümü de iyi: workspace'ler, pnpm, Turborepo, Nx, Lerna ve Rush üzerine.23

  6. Sıfırdan başlamak için Anthony Shew'nun How to structure a JS/TS monorepo videosu, yalnızca pnpm tarafını görmek için de Code with tkssharma'nın PNPM Workspaces Deep Dive videosu var. İkincisinde pnpm-workspace.yaml ile api ve utils paketi kurulup workspace: ile bağlanıyor.24

  7. Bir uygulamanız varsa turbo prune <uygulama> --docker çalıştırın ve out/json ile out/full klasörlerine bakın.22

Kaynaklar

  • 1MakaleThe New Stack: The Case for (and Against) Monorepos on the Frontend

    Monorepo'nun frontend'de iş birliği maliyetine etkisi ve geçişin organizasyonel yönü.

  • 2MakaleGraphite: When to use a monorepo

    Monorepo'nun uygun ve uygun olmadığı durumlar.

  • 3AraştırmaRachel Potvin ve Josh Levenberg: Why Google Stores Billions of Lines of Code in a Single Repository

    Google'ın tek repo modelinin gerekçeleri, avantajları ve ödünleşimleri. Communications of the ACM, 2016.

  • 4VideoFireship: Monorepos, How the Pros Scale Huge Software Projects // Turborepo vs Nx

    Monorepo'nun faydası ve boyut maliyeti, Nx ile Turborepo karşılaştırması ve `create-turbo` demosu. 9 dk, 2021.

  • 5Makaletechinterview.org: Frontend Monorepos, Turborepo, Nx, and the State of 2026

    Ne zaman benimsenir, Turborepo ile Nx farkı ve 2026 pratikleri. Haziran 2026 güncellemesi, yazar belirtilmemiş.

  • 6Dokümanpnpm: Workspace

    `pnpm-workspace.yaml`, `workspace:` protokolü ve tek lockfile.

  • 7DokümanTurborepo: Configuring tasks

    `tasks`, `dependsOn`, `^`, `outputs` ve paralel çalıştırma.

  • 8DokümanTurborepo: Caching

    Parmak izi tabanlı önbellek, Remote Cache ve global hash girdileri.

  • 9DokümanTurborepo: Structuring a repository

    `apps/` ve `packages/` yapısı, paket anatomisi, `exports` ve `@repo` öneki.

  • 10DokümanTurborepo: Managing dependencies

    Bağımlılığı kullanıldığı pakete kurma, kök dizinde az bağımlılık ve sürümleri eşitleme.

  • 11DokümanNx: Enforce module boundaries

    Nx'in mimari sınırları zorlama mekanizmaları.

  • 12VideoAnthony Shew: How to structure a JS/TS monorepo, From Zero to Turbo

    Workspace'ler, `apps` ve `packages` yapısı, `exports`, paket adıyla erişim, Turborepo görevleri ve Remote Cache.

  • 13VideoTally Barak: 1001 Packages, Strategies for Managing Monorepos (DevOps.js Conf 2022)

    Paket kurulumu, bağlama, build stratejileri, hoisting uyarısı ve sürümleme. 24 dk.

  • 14DokümanTurborepo: Internal Packages

    `workspace:*` ile kullanım, Just-in-Time ve Compiled paket stratejileri.

  • 15Dokümanpnpm: Catalogs

    Sürümleri `catalog:` protokolüyle tek yerde tutma.

  • 16DokümanTurborepo: Creating an Internal Package

    Paket oluşturma adımları, tek amaçlı paketler ve uygulamalarda paylaşılan kod barındırmama.

  • 17DokümanTurborepo: TypeScript

    Paylaşılan `tsconfig` paketi, Node.js subpath imports ve kök `tsconfig`'e ihtiyaç duyulmaması.

  • 18Dokümanshadcn/ui: Monorepo

    `init --monorepo`, `packages/ui` yapısı ve `components.json` gereksinimleri.

  • 19DokümanTurborepo: Running tasks

    `turbo run`, `--filter` kalıpları ve kök script'lerde kullanım.

  • 20VideoMichael Guay: Learn Turborepo By Example, Code Sharing, Distributed Cache, & More!

    Next.js ve NestJS'i tek workspace'te kurma, paylaşılan paketler, GitHub Actions ve Vercel Remote Cache, `turbo prune` ile Docker.

  • 21DokümanTurborepo: Docker

    Monorepo'da Docker build'inin neden bozulduğu, `turbo prune --docker`, çok aşamalı Dockerfile ve Remote Cache argümanları.

  • 22DokümanTurborepo: prune

    `turbo prune` sözdizimi, `--docker` çıktısı (`json/`, `full/`, budanmış kilit dosyası) ve seçenekler.

  • 23Syntax #426: Monorepos! Workspaces, pnpm, turborepo + more!

    (podcast) — Wes Bos ve Scott Tolinski'den monorepo deneyimi, paylaşılan bağımlılıklar ve araçlar. Ocak 2022.

  • 24VideoCode with tkssharma: PNPM Workspaces Deep Dive, Fast Monorepo Setup

    `pnpm-workspace.yaml` kurulumu, alt paket oluşturma ve `workspace:` ile yerel bağımlılık ekleme.

Bu sayfayı düzenle

Son güncelleme tarihi: 15 Ekim 2026

Önceki adım03. Proje Yapısını DüzenlemeProje
Sonraki adım05. Micro Frontend