한땀한땀

[아키텍처 탐험기 1부] 모노레포 도입 여정: Turborepo와 pnpm으로 단단한 기반 다지기 본문

FrontEnd Dev

[아키텍처 탐험기 1부] 모노레포 도입 여정: Turborepo와 pnpm으로 단단한 기반 다지기

junfromkorea 2025. 9. 2. 09:35

안녕하세요, 이번 아키텍처 탐험기 시리즈에서는 거대한 프론트엔드 모노리스(Monolith) 구조에서 벗어나, 마이크로 프론트엔드(MFE) 아키텍처를 성공적으로 구축한 여정을 공유하고자 합니다. 총 3부에 걸쳐 연재될 이 시리즈의 첫 번째 이야기는 모든 것의 기반이 되는 모노레포(Monorepo) 도입기입니다.

 

배경: 두 마리 토끼를 잡아야 했다

 

MFE 아키텍처 도입의 전제는 '독립성'이었습니다. 각 기능 앱은 독립적으로 배포되어야 했습니다. 하지만 동시에 디자인 시스템, 공통 유틸, 타입 정의 같은 공유 모듈은 단일 소스(Single Source of Truth)로 일관되게 관리되어야 했습니다. 이 두 가지 상충하는 요구사항을 어떻게 동시에 만족시킬 것인가가 첫 번째 과제였습니다.

 

고민의 과정: 대안들과 그 한계

 

1. 멀티레포(Multi-repo) + 패키지 퍼블리시: 처음에는 각 앱과 모듈을 별도의 레포지토리에서 관리하는 방식을 고려했습니다. 앱의 완전한 독립성을 보장하고 권한 관리에도 용이해 보였습니다. 하지만 현실은 달랐습니다. 사소한 타입 변경 하나에도 버전 업데이트, 패키지 퍼블리시, 변경 로그 작성이 필요해 개발 리드타임이 급격히 늘어났습니다. 더 큰 문제는, 소비하는 앱에서 업데이트가 늦어지며 발생하는 버전 스큐(Version Skew)였습니다. 공통 모듈 변경과 이를 사용하는 앱의 반영을 하나의 PR에서 원자적으로 검증할 수 없어 릴리즈 리스크가 항상 존재했습니다.

 

2. 단일 레포(Single-repo) 내 폴더 분리: 그렇다면 하나의 레포지토리에서 관리하는 것은 어떨까요? 코드 탐색은 편리했지만, 근본적인 문제가 있었습니다. 어떤 코드가 변경되었을 때 어떤 앱이 영향을 받는지 추적할 수 없었고, 빌드 캐시나 병렬 처리 같은 최적화 도구가 없어 작은 수정에도 전체 프로젝트를 다시 빌드해야 했습니다. CI 시간은 계속해서 길어졌습니다.

 

최종 설계와 그 이유: Turborepo + pnpm workspaces

 

결론은 명확했습니다. 작업 그래프를 이해하여 빌드 캐싱, 병렬 처리, 변경 영향 분석(affected filter)을 지원하고, 공통 모듈과 앱의 변경을 원자적으로 검증할 수 있는 모노레포 빌드 시스템이 필요했습니다.

  • pnpm workspaces: workspace: 프로토콜을 통해 별도의 퍼블리시 과정 없이 공유 모듈을 즉시 가져다 쓸 수 있게 했습니다. 덕분에 공통 모듈과 소비 앱의 변경을 하나의 PR에서 원자적으로 검증하는 것이 가능해졌습니다.
  • Turborepo: Nx에 비해 러닝커브가 낮고 간결한 설정(turbo.json)만으로도 저희가 필요로 했던 빌드 파이프라인, 원격 캐시, 변경 영향 필터 기능을 충분히 제공해 주어 빠른 안정화를 이룰 수 있었습니다.

예시:

//pnpm-workspace.yaml

packages:
  - 'apps/*'
  - 'packages/*'
// /turbo.json
{
  "$schema": "https://turborepo.org/schema.json",
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", ".next/**"]
    },
    "lint": {},
    "dev": { "cache": false, "persistent": true }
  }
}
// 공유 패키지를 사용하는 앱
// /apps/host-app/package.json
{
  "name": "host-app",
  "dependencies": {
    "@my-org/ui-library": "workspace:*"
  }
}

 

도입 효과 (Impact)

  • 릴리즈 안정성 향상: 공통 모듈과 앱 변경을 원샷으로 검증하고 머지하여 릴리즈 안정성이 크게 향상되었습니다.
  • 개발 경험(DX) 개선: Turbo 캐시와 pnpm으로 CI 대기 및 빌드 시간이 대폭 단축되었고, 로컬 환경에서의 즉시성도 개선되었습니다.
  • 품질 및 일관성 강화: 디자인 시스템, 분석 SDK 등을 단일 소스로 유지하여 일관성, 재사용성, 품질을 동시에 강화했습니다.

앞으로의 과제

 

모노레포가 커질수록 의존성 그래프가 복잡해질 수 있습니다. 향후에는 코드 소유권(Code Ownership)을 명확히 하고, 의존성 규칙을 강제하는 린트 룰을 도입하여 아키텍처의 경계를 더욱 견고하게 유지할 계획입니다.

 

이제 코드베이스를 효율적으로 관리할 수 있는 단단한 기반이 마련되었습니다. 하지만 이것은 시작에 불과합니다.

 

다음 2부에서는 이 모노레포 위에서 어떻게 각 애플리케이션의 독립적인 배포를 실현했는지, Webpack Module Federation 

도입기를 자세히 다뤄보겠습니다.