모노레포 · 워크스페이스 패턴

모노레포(Monorepo)의 개념과 Node.js 워크스페이스 설정 방법을 설명합니다. pnpm workspaces, workspace:* 프로토콜, Turborepo 빌드 파이프라인, 공유 설정 패키지, 버전 관리 전략을 실전 예제로 다룹니다.

· 4 min read · PALDYN Team

지난 글에서 SemVer와 버전 범위 표기를 살펴봤습니다. 규모가 커진 프로젝트는 여러 패키지로 분리되는데, 이를 하나의 레포지터리에서 관리하는 방식이 모노레포입니다. 공유 코드 재사용, 일관된 빌드 도구, 원자적 커밋이 장점입니다.


모노레포 구조

모노레포 워크스페이스 구조


pnpm 워크스페이스 설정

# pnpm-workspace.yaml
packages:
  - 'packages/*'
  - 'apps/*'
  - 'tooling/*'
// 루트 package.json
{
  "name": "my-monorepo",
  "private": true,
  "scripts": {
    "build": "turbo build",
    "dev":   "turbo dev",
    "test":  "turbo test",
    "lint":  "turbo lint"
  },
  "devDependencies": {
    "turbo": "^2.0.0"
  }
}

"private": true는 루트를 npm에 배포하지 않게 막습니다.


workspace 프로토콜

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

workspace:*는 로컬 패키지를 심링크로 연결합니다. npm publish/pnpm publish 시 실제 버전 번호로 자동 치환됩니다.

# 특정 워크스페이스에 의존성 추가
pnpm add react --filter web
pnpm add typescript --filter '@myorg/*' -D

# 루트에 공유 devDependency 추가
pnpm add -Dw prettier

설정 파일 예시

모노레포 설정 파일 예시


Turborepo 빌드 파이프라인

# Turborepo 설치
pnpm add -Dw turbo

# 전체 빌드 (의존성 순서 자동 처리)
pnpm turbo build

# 특정 패키지만
pnpm turbo build --filter=web

# 변경된 패키지만 (Git diff 기반)
pnpm turbo build --filter='[HEAD~1]'

Turborepo는 이전 빌드 결과를 캐시합니다. 소스가 변경되지 않은 패키지는 캐시에서 즉시 복원합니다. 원격 캐시를 설정하면 팀 전체가 캐시를 공유합니다.

// turbo.json
{
  "remoteCache": {
    "enabled": true
  },
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs":   ["dist/**", ".next/**"],
      "cache":     true
    },
    "test": {
      "dependsOn": ["build"],
      "outputs":   ["coverage/**"]
    },
    "lint": {
      "outputs": []
    }
  }
}

"^build"^는 의존하는 패키지의 build가 먼저 완료되어야 함을 의미합니다.


공유 설정 패키지

tooling/
  eslint-config/
    index.js
    package.json  ← "name": "@myorg/eslint-config"
  tsconfig/
    base.json
    nextjs.json
    package.json  ← "name": "@myorg/tsconfig"
// apps/web/package.json의 devDependencies
{
  "@myorg/eslint-config": "workspace:*",
  "@myorg/tsconfig": "workspace:*"
}
// apps/web/tsconfig.json
{
  "extends": "@myorg/tsconfig/nextjs.json",
  "include": ["src", "next-env.d.ts"],
  "compilerOptions": {
    "baseUrl": "."
  }
}

버전 관리 전략

전략설명도구
고정 버전모든 패키지가 같은 버전Lerna fixed mode
독립 버전패키지별 독립 버전Lerna independent, changeset
배포 없음내부용 — 버전 불필요루트 scripts만 사용
# changeset으로 독립 버전 관리
pnpm changeset add          # 변경 기록
pnpm changeset version      # 버전 범프
pnpm changeset publish      # 배포

nx vs Turborepo

TurborepoNx
설정 복잡도낮음높음
플러그인 생태계작음풍부함
원격 캐시유료(Vercel) / 오픈소스유료(Nx Cloud) / 오픈소스
태스크 그래프 시각화CLIGUI

지난 글: SemVer · Node.js 버전 관리 전략

다음 글: node_modules 호이스팅과 의존성 해석


읽어주셔서 감사합니다. 😊