Monorepo를 언제 사용해야 할까
Source: Dev.to

Source: …
정말 모노레포가 필요할까?
많은 팀에게 솔직한 답은: 처음엔 아마 필요하지 않을 수도 있지만— 왜 모노레포가 필요하다고 생각하는지에 따라 크게 달라집니다.
대부분의 팀은 서비스와 프론트엔드 사이에서 코드와 타입을 중복하는 데 지쳐 모노레포 이야기를 시작합니다. 이야기는 익숙합니다: 백엔드부터 시작하고, 프론트엔드를 추가하고, 혹은 모바일 앱을 만들면서 어느새 타입, 요청/응답 형태, 유틸리티 등을 여기저기 복사‑붙여넣기하게 됩니다. npm 패키지를 추출해 보려다 유지보수와 버전 관리가 고통스럽다는 것을 깨닫고, 그때부터 Turborepo나 Nx 같은 모노레포 솔루션을 진지하게 검토하게 됩니다.
모노레포는 여러 앱, 서비스, 라이브러리를 하나의 저장소에 담는 방식입니다. Google과 Meta 같은 기업이 유명하게 만들었고, Turborepo와 Nx 같은 도구가 이 모델을 일상적인 팀에도 도입하게 했습니다.
전형적인 동기는 다음과 같습니다:
- 여러 프로젝트 간에 공유되는 코드와 타입 정의
- 간소화된 의존성 관리
- 일관된 도구 체인 및 CI 파이프라인
- 전체 코드베이스에 걸친 리팩터링 용이
이러한 이점은 실제로 존재하지만, 동시에 눈에 띄는 트레이드오프도 동반합니다.
모노레포의 숨겨진 비용
매력에도 불구하고 모노레포는 무료가 아닙니다. Nx와 Turborepo 같은 도구는 강력하지만 상당한 복잡성과 학습 곡선을 동반합니다. 특히 Nx는 정교한 빌드 시스템이자 프로젝트‑그래프 관리자로서 작업‑그래프 분석, 증분 빌드 및 캐싱, 플러그인 생태계를 제공합니다.
Nx를 실제로 활용하려면 팀이 다음에 대한 탄탄한 이해가 필요합니다:
- TypeScript 프로젝트 레퍼런스
- 경로 매핑 및 모듈 해석
- 빌드 타깃(
build,test,lint)이 어떻게 구성되는지
TypeScript와 도구 사용에 익숙하지 않은 팀, 혹은 경험이 부족한 팀에게는 큰 장벽이 될 수 있습니다. 도구가 마법처럼 보이다가 문제가 발생하면 디버깅이 어려워집니다. 문서에 나와 있는 Nx의 방대한 기능은 이러한 복잡성을 암시합니다.
시간이 지나면서 단순한 변경이 널리 퍼져 나가면서 위험과 인지 부하가 증가하는, 밀접하게 결합된 시스템이 될 수 있습니다. 툴링과 CI도 도전 과제가 됩니다. 모노레포 도구가 더 빠른 빌드를 약속하지만, 잘못된 설정은 다음을 초래할 수 있습니다:
- 불필요한 재빌드로 인한 CI 시간 증가
- 조정하기 어려운 복잡한 캐싱 전략
- 추적하기 힘든 의존성으로 인한 예기치 않은 파손
CI와 개발 툴을 신중하게 튜닝하지 않으면, 여러 개의 단순한 레포지토리를 사용하는 것보다 상황이 악화되어 모노레포 도입 초기 목적을 무색하게 만들 수 있습니다.
모노레포 대안
모노레포를 도입하기 전에 많은 팀이 중복을 피하기 위해 공유 npm 패키지를 실험합니다. 공통 코드를 @your-org/api-types 혹은 @your-org/utils와 같은 패키지로 추출하고, 사설 레지스트리(예: GitHub Packages 또는 자체 호스팅 npm)에서 호스팅한 뒤 프론트엔드와 백엔드 모두에서 해당 패키지를 사용합니다.
이 접근법은 일부 문제를 해결하지만 새로운 문제를 야기합니다:
- 버전 관리 오버헤드 – 모든 변경마다 버전을 올리고, 배포하고, 모든 사용 애플리케이션을 업데이트해야 함.
- 드리프트 – 백엔드와 프론트엔드가 동시에 업그레이드되지 않으면 미묘한 호환성 문제가 발생.
- 인프라 비용 – 사설 레지스트리 유지, 인증 관리, 공유 라이브러리를 위한 별도 CI 파이프라인 운영.
팀이 모노레포를 선택하는 핵심 이유 중 하나는 동일한 타입과 클라이언트를 여러 곳에서 다시 작성하는 일을 피하고 싶기 때문입니다. 공유 TypeScript 라이브러리를 수동으로 관리하는 대신, API 명세에서 타입과 클라이언트 코드를 자동으로 생성하는 방법도 있습니다.
API가 OpenAPI 또는 Swagger로 잘 정의돼 있다면, 각 소비자를 위해 타입과 클라이언트 코드를 생성할 수 있습니다. Hey API와 같은 도구는 OpenAPI 명세를 받아 웹, 모바일, 기타 환경용 TypeScript 타입과 API 클라이언트 코드를 출력합니다. 이 모델에서는 OpenAPI 문서가 백엔드와 프론트엔드 사이의 계약이 되어, 공유 TypeScript 코드를 공유 명세로 대체합니다.
API 명세 기반 개발의 장점
- API 계약에 대한 단일 진실 원천
- 최신 타입과 클라이언트의 자동 생성
- 서비스 간 수동 동기화 필요 감소
- 코드 생성기(예: OpenAPI Generator,
openapi-typescript)를 통한 다중 언어·플랫폼 호환성
모노레포가 의미가 있을 때
모노레포가 추가적인 복잡성을 감수할 만큼 가치가 있는 명확한 상황들이 있습니다. 여러 개의 애플리케이션을 활발히 개발하면서 코드가 많이 공유되는 경우—예를 들어:
- 관리자 패널, 공개 웹 앱, 여러 백엔드 서비스, 그리고 공유 UI 라이브러리
- 빈번한 프로젝트 간 협업 및 리팩토링
- 전체 코드베이스에 걸친 일관된 린팅, 테스트, 빌드 파이프라인 필요
와 같은 환경에서는 코드 재사용이 크게 이루어지며, 통합 저장소의 이점이 오버헤드보다 클 수 있습니다.
원본은 make-it.run에서 처음 게시되었습니다.