Advanced (Diperbarui: 1/6/2026)

Mengelola Monorepo dengan Claude Code: pnpm, Turborepo, Nx, dan CI

Panduan monorepo Claude Code: repo map, pnpm workspace, affected tasks, CODEOWNERS, dependency policy, dan CI.

Mengelola Monorepo dengan Claude Code: pnpm, Turborepo, Nx, dan CI

Monorepo adalah struktur ketika beberapa aplikasi dan library dikelola dalam satu repository Git. Dengan pola seperti apps/web, apps/api, packages/ui, dan packages/shared, tim bisa berbagi tipe, komponen UI, konfigurasi, dan CI. Tetapi tanpa batas yang jelas, Claude Code bisa membuat perubahan terlalu luas: satu edit kecil di packages/shared dapat memengaruhi beberapa aplikasi sekaligus.

Workflow yang aman adalah membuat repo map terlebih dahulu, menentukan package boundaries, menggunakan pnpm workspace dan workspace:*, lalu menjalankan affected tasks dengan Turborepo atau Nx. Untuk rujukan resmi, lihat Nx why monorepos, Nx affected, Nx mental model, pnpm, dan Turborepo docs.

Struktur yang dituju

Sebelum meminta Claude Code mengedit, minta ia memahami arsitektur repository.

graph TD
  WEB["apps/web"] --> UI["packages/ui"]
  WEB --> SHARED["packages/shared"]
  API["apps/api"] --> SHARED
  UI --> CONFIG["packages/config"]
  SHARED --> CONFIG
  CI["CI affected tasks"] --> WEB
  CI --> API

apps/* adalah aplikasi yang dideploy. packages/* adalah modul yang dipakai ulang. Package boundary adalah aturan tentang package mana yang boleh bergantung pada package lain. Aturan ini harus diberikan secara eksplisit kepada Claude Code.

Prompt awal untuk Claude Code

Analisis repository ini sebagai monorepo.

Asumsi:
- apps/web adalah aplikasi Next.js
- apps/api adalah API server
- packages/ui berisi reusable UI
- packages/shared berisi type, validation, dan pure function
- packages/config berisi ESLint, TypeScript, Prettier, dan konfigurasi test

Aturan:
- apps/* tidak boleh bergantung langsung pada apps/*
- packages/* tidak boleh bergantung pada apps/*
- internal package harus memakai workspace:*
- setelah perubahan, lint/test/build dijalankan sebagai affected tasks

Pertama buat repo map: dependencies, risky cycles, file yang terlalu dibagi, dan command CI untuk verifikasi.
Jangan edit file dulu.

Kalimat terakhir penting. Dalam monorepo, risiko utama sering bukan syntax error, melainkan arah dependency yang salah.

pnpm workspace

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

Di package.json root, siapkan command yang konsisten.

{
  "name": "acme-monorepo",
  "private": true,
  "packageManager": "pnpm@10.12.1",
  "scripts": {
    "build": "turbo run build",
    "lint": "turbo run lint",
    "test": "turbo run test",
    "typecheck": "turbo run typecheck",
    "ci:affected": "turbo run lint test build --affected",
    "check:deps": "node scripts/check-workspace-deps.cjs"
  }
}

Internal dependency ditulis dengan workspace:*.

{
  "dependencies": {
    "@acme/shared": "workspace:*",
    "@acme/ui": "workspace:*"
  }
}

Prompt yang lebih aman:

Buat apps/web dapat menggunakan @acme/ui dan @acme/shared.
Gunakan workspace:* di package.json.
Jangan buat import lewat ../../packages.
Perubahan harus bisa diverifikasi dengan pnpm check:deps dan pnpm ci:affected.

Turborepo dan Nx affected

Turborepo cocok ketika setiap package sudah punya scripts sendiri.

{
  "$schema": "https://turbo.build/schema.json",
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", ".next/**", "!.next/cache/**"]
    },
    "lint": {
      "dependsOn": ["^build"]
    },
    "test": {
      "dependsOn": ["^build"],
      "outputs": ["coverage/**"]
    },
    "typecheck": {
      "dependsOn": ["^build"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    }
  }
}

Nx berguna ketika tim membutuhkan project graph dan analisis affected yang lebih kuat.

pnpm dlx nx@latest init
pnpm nx affected -t lint test build --base=origin/main --head=HEAD

Untuk Claude Code, gunakan instruksi “jalankan checks yang affected” daripada “jalankan semuanya”. Ini menjaga CI tetap cepat dan murah.

CODEOWNERS dan dependency policy

/apps/web/ @acme/frontend
/apps/api/ @acme/backend
/packages/ui/ @acme/design-system
/packages/shared/ @acme/platform
/packages/config/ @acme/platform
/pnpm-workspace.yaml @acme/platform
/turbo.json @acme/platform

Policy juga perlu dicek dengan code. Simpan sebagai scripts/check-workspace-deps.cjs.

const fs = require("node:fs");
const path = require("node:path");

const ROOT = process.cwd();
const WORKSPACE_DIRS = ["apps", "packages"];
const DEP_FIELDS = ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"];

function readJson(file) {
  return JSON.parse(fs.readFileSync(file, "utf8"));
}

function findPackageDirs(baseDir) {
  const absoluteBase = path.join(ROOT, baseDir);
  if (!fs.existsSync(absoluteBase)) return [];
  return fs
    .readdirSync(absoluteBase, { withFileTypes: true })
    .filter((entry) => entry.isDirectory())
    .map((entry) => path.join(absoluteBase, entry.name))
    .filter((dir) => fs.existsSync(path.join(dir, "package.json")));
}

const packages = WORKSPACE_DIRS.flatMap(findPackageDirs).map((dir) => {
  const manifest = readJson(path.join(dir, "package.json"));
  return { dir, name: manifest.name, manifest };
});

const byName = new Map(packages.map((pkg) => [pkg.name, pkg]));
let failed = false;

for (const pkg of packages) {
  for (const field of DEP_FIELDS) {
    const deps = pkg.manifest[field] || {};
    for (const [name, range] of Object.entries(deps)) {
      const internal = byName.get(name);
      if (!internal) continue;
      const fromDir = path.relative(ROOT, pkg.dir).replace(/\\/g, "/");
      const toDir = path.relative(ROOT, internal.dir).replace(/\\/g, "/");

      if (!String(range).startsWith("workspace:")) {
        console.error(`${pkg.name}: ${name} must use workspace:* in ${field}`);
        failed = true;
      }
      if (toDir.startsWith("apps/")) {
        console.error(`${pkg.name}: ${fromDir} must not depend on app package ${toDir}`);
        failed = true;
      }
    }
  }
}

if (failed) process.exit(1);
console.log(`Checked ${packages.length} workspace packages.`);

Checklist CI

name: monorepo-ci

on:
  pull_request:
  push:
    branches: [main]

jobs:
  checks:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: pnpm/action-setup@v4
        with:
          version: 10
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: pnpm
      - run: pnpm install --frozen-lockfile
      - run: pnpm check:deps
      - run: pnpm ci:affected

fetch-depth: 0 diperlukan karena affected checks membutuhkan Git history yang cukup.

Use case praktis

  1. Mengubah Button di packages/ui. Claude Code harus menjaga public API tetap stabil dan mencantumkan screen yang terdampak di apps/web.

  2. Memindahkan shared DTO ke packages/shared. DTO adalah bentuk data untuk API dan UI, bukan model database.

  3. Upgrade TypeScript, Next.js, atau testing tools. Mulai dari packages/config, lalu verifikasi aplikasi yang affected.

  4. Menambahkan fitur lintas tim seperti billing, search, atau onboarding. Minta Claude Code membagi pekerjaan menjadi beberapa PR kecil.

Pitfall yang sering terjadi

Pertama, packages/shared menjadi tempat menaruh semua hal. Simpan hanya code yang stabil, generik, dan mudah dites.

Kedua, memakai import relatif seperti ../../packages/shared/src. Ini melewati package boundary dan membuat build sulit dilacak.

Ketiga, mengadopsi Turborepo dan Nx terlalu dalam sekaligus. Pilih satu model utama dulu.

Keempat, menganggap “jalan di lokal” sudah cukup. PR harus menyebut package yang berubah, aplikasi terdampak, command yang dijalankan, dan risiko tersisa.

Prompt review

Review diff ini dari sudut pandang monorepo.

Cek:
- tidak ada dependency langsung dari apps/* ke apps/*
- packages/* tidak bergantung pada apps/*
- internal dependencies memakai workspace:*
- packages/shared hanya berisi stable shared code
- affected lint/test/build sudah cukup
- CODEOWNERS jelas menunjukkan reviewer

Return:
- blocker
- rekomendasi perbaikan
- command yang sudah diverifikasi
- ringkasan impact untuk PR body

Lanjutkan dengan Claude Code dan Nx workspace, Claude Code dan pnpm workspace, Claude Code dengan Turborepo, dan kolaborasi tim dengan Claude Code.

Jika tim ingin memakai Claude Code di monorepo nyata, hal utama adalah boundary, owner, CI, dan prompt review. ClaudeCodeLab dapat membantu melalui training dan konsultasi Claude Code dengan CLAUDE.md, CODEOWNERS, CI, dan PR workflow berbasis repository nyata.

Ringkasan

Claude Code efektif untuk monorepo jika constraint jelas. Repo map, package boundaries, pnpm workspace, Turborepo/Nx affected tasks, CODEOWNERS, dependency policy, dan CI checklist mengubah output AI menjadi workflow engineering yang bisa diulang. Dalam praktik, memaksa workspace:* dan menstandarkan pnpm ci:affected langsung mengurangi review miss dan full CI yang tidak perlu.

#Claude Code #monorepo #pnpm workspace #Turborepo #Nx
Gratis

PDF gratis: cheatsheet Claude Code

Masukkan email dan unduh satu halaman berisi command, kebiasaan review, dan workflow aman.

Kami menjaga datamu dan tidak mengirim spam.

Masa

Tentang penulis

Masa

Engineer yang berfokus pada workflow Claude Code praktis dan adopsi tim.