
모노레포는 대규모 프로젝트 관리의 해결책처럼 보였다. 코드 공유가 쉬워지고, 일관성 있는 개발 환경을 만들 수 있다는 매력에 빠져 우리 팀은 멀티레포에서 모노레포로 전환하기로 결정했다. 하지만 3개월 후, 우리는 다시 멀티레포로 돌아갔다. 이 글은 그 실패 과정을 솔직하게 기록한 것이다.
시작: 모노레포에 대한 환상
왜 모노레포를 선택했나
우리 팀은 5개의 서로 다른 저장소를 관리하고 있었다. 프론트엔드, 백엔드 API, 관리자 페이지, 모바일 앱, 공유 라이브러리. 각각 독립적으로 개발되고 있었지만, 공유 라이브러리를 업데이트할 때마다 5개 저장소를 모두 수정해야 하는 불편함이 있었다.
“모노레포로 옮기면 코드 공유가 쉬워지고, 빌드도 빠르고, 일관성도 유지할 수 있을 거야.” 이렇게 생각하며 Turborepo를 선택했다. 문서를 보니 멋져 보였다. 캐싱도 되고, 병렬 빌드도 되고.
초기 기대감
2025년 9월, 모노레포 전환 프로젝트를 시작했다. 팀원들도 대부분 긍정적이었다. “코드 공유가 쉬워지면 좋겠다”, “빌드 시스템이 통일되면 편할 것 같다”는 반응이었다.
처음 한 달은 순조로웠다. 기존 저장소들을 apps/와 packages/ 폴더로 옮기고, turbo.json을 설정했다. 간단한 프로젝트부터 시작해서 점진적으로 옮기기로 했다.
첫 번째 문제: 빌드 시간 폭증
예상과 다른 현실
문서에는 “캐싱으로 빌드 시간이 단축된다”고 되어 있었다. 하지만 우리의 경우는 달랐다.
이전 (멀티레포):
- 프론트엔드 빌드: 2분
- 백엔드 빌드: 1분
- 총 빌드 시간: 3분 (병렬 실행 시)
모노레포 전환 후:
- 전체 빌드: 8분
- 캐싱 후에도: 5분
왜 이렇게 느려졌을까? Turborepo가 의존성 그래프를 분석하고, 각 패키지를 순차적으로 빌드하는 과정에서 오버헤드가 발생했다. 작은 변경사항 하나만 있어도 전체 의존성을 다시 확인해야 했다.
팀원들의 불만
빌드 시간이 늘어나면서 개발 속도가 느려졌다. 특히 CI/CD 파이프라인에서 문제가 심각했다.
“작은 수정 하나 하는데 왜 이렇게 오래 걸려?” “이전에는 5분이면 되던 게 지금은 15분이 걸려.”
팀원들의 불만이 쌓이기 시작했다. 나도 답답했다. 분명히 더 빨라질 거라고 생각했는데.
두 번째 문제: 의존성 지옥
순환 의존성 발견
모노레포로 옮기면서 숨어있던 문제들이 드러났다. 가장 큰 문제는 순환 의존성이었다.
apps/frontend → packages/shared-ui
packages/shared-ui → packages/utils
packages/utils → apps/frontend (???)이런 순환 의존성이 있었다. 멀티레포였을 때는 각 저장소가 독립적이라 문제가 되지 않았지만, 모노레포에서는 빌드 순서를 결정할 수 없어서 에러가 발생했다.
버전 충돌
각 앱이 사용하던 라이브러리 버전이 달랐다. 예를 들어:
- 프론트엔드: React 18.2
- 관리자 페이지: React 18.0
- 공유 라이브러리: React 18.2
모노레포에서는 루트에 설치된 버전을 공유해야 했는데, 버전이 달라서 호환성 문제가 발생했다. 모든 앱을 같은 버전으로 업그레이드하려니 다른 문제들이 생겼다.
세 번째 문제: Git 히스토리와 충돌
히스토리 통합의 어려움
기존 저장소들의 Git 히스토리를 통합하는 것도 문제였다. git subtree를 사용해서 옮겼지만, 히스토리가 복잡해졌다.
더 큰 문제는 충돌이었다. 여러 개발자가 동시에 작업할 때, 같은 파일을 수정하는 경우가 많아졌다. 멀티레포였을 때는 각 저장소가 독립적이라 충돌이 적었지만, 모노레포에서는 자주 발생했다.
브랜치 관리의 복잡성
브랜치 전략도 복잡해졌다. 각 앱별로 브랜치를 만들어야 했는데, 모노레포에서는 하나의 브랜치에 모든 변경사항이 들어갔다. 리뷰하기도 어려워졌다.
네 번째 문제: 팀 내부 갈등
개발자들의 반발
3개월이 지나면서 팀원들의 불만이 커졌다.
“이전 방식이 더 나았어.” “왜 이렇게 복잡하게 만들었어?” “빌드만 하면 10분씩 걸려.”
특히 주니어 개발자들이 힘들어했다. 모노레포 구조를 이해하는 것도 어려웠고, 빌드 에러를 해결하는 것도 복잡했다.
내 고민
나도 고민이 많았다. 분명히 좋은 선택이라고 생각했는데, 현실은 달랐다. 팀원들의 불만을 보면서 “내가 잘못 선택한 건가?”라는 생각이 들었다.
하지만 이미 3개월을 투자했고, 되돌리기엔 너무 많은 작업이 필요했다. 그래도 계속 밀어붙였지만, 상황은 나아지지 않았다.
결국 되돌리기로 결정
결정의 순간
2025년 12월, 팀 회의에서 모노레포를 포기하기로 결정했다. 3개월 동안의 시도가 실패로 끝났다.
결정 이유:
- 빌드 시간이 오히려 늘어났다
- 개발 속도가 느려졌다
- 팀원들의 불만이 커졌다
- 복잡도만 증가했다
되돌리는 과정
되돌리는 것도 쉽지 않았다. 각 앱을 다시 독립적인 저장소로 분리해야 했다. Git 히스토리를 복원하고, 의존성을 다시 설정하고, CI/CD 파이프라인을 수정했다. 한 달이 더 걸렸다.
배운 점들
1. 모든 프로젝트에 모노레포가 적합한 것은 아니다
우리 팀의 경우, 각 앱이 독립적으로 배포되고, 팀도 분리되어 있었다. 이런 상황에서는 모노레포가 오히려 복잡도만 증가시켰다.
모노레포가 적합한 경우:
- 팀이 하나로 통합되어 있을 때
- 코드 공유가 매우 많을 때
- 배포가 함께 이루어질 때
멀티레포가 나은 경우:
- 각 앱이 독립적으로 운영될 때
- 팀이 분리되어 있을 때
- 배포 주기가 다를 때
2. 기술 선택은 팀 상황을 고려해야 한다
트렌드를 따라가는 것보다, 팀의 상황과 프로젝트의 특성을 고려하는 것이 중요하다. 우리는 “모노레포가 트렌드니까”라는 이유로 선택했지만, 우리 팀에는 맞지 않았다.
3. 점진적 도입이 중요하다
한 번에 모든 것을 옮기려고 하지 말고, 작은 프로젝트부터 시작해서 문제를 파악하고 개선하는 것이 중요하다. 우리는 너무 성급했다.
4. 실패를 빠르게 인정하는 용기
3개월이나 걸렸지만, 결국 실패를 인정하고 되돌렸다. 이 결정이 쉽지 않았지만, 지금 생각해보면 더 빨리 결정했어야 했다.
지금은 어떻게 하고 있나
개선된 멀티레포 전략
모노레포로 돌아간 후, 우리는 멀티레포를 개선했다:
공유 라이브러리 관리:
- npm private registry 사용
- 버전 관리 체계화
- 자동 업데이트 스크립트
빌드 시스템:
- GitHub Actions로 통합
- 병렬 빌드 최적화
- 캐싱 전략 개선
문서화:
- 각 저장소의 역할 명확화
- 의존성 관계 문서화
- 온보딩 가이드 작성
현재 상태
지금은 멀티레포로 잘 운영하고 있다. 각 팀이 독립적으로 작업하면서도, 필요한 부분만 공유하는 방식이다. 빌드 시간도 줄었고, 개발 속도도 향상되었다.
다른 개발자들에게
모노레포를 고려한다면
모노레포를 도입하려는 팀이 있다면, 다음을 고려해보길 바란다:
- 팀 구조를 먼저 확인하라: 팀이 통합되어 있는가?
- 작은 프로젝트부터 시작하라: 전체를 한 번에 옮기지 말라
- 빌드 시간을 측정하라: 실제로 빨라지는지 확인하라
- 팀원들의 피드백을 듣라: 불만이 쌓이기 전에 조치하라
실패를 두려워하지 말라
우리의 실패 경험이 다른 팀에게는 도움이 될 수 있다. 실패를 통해 배운 것들이 많다. 모노레포가 우리 팀에 맞지 않았을 뿐, 다른 팀에게는 적합할 수 있다.
결론: 실패에서 배운 것
모노레포 도입은 실패했지만, 이 경험을 통해 많은 것을 배웠다. 기술 선택의 중요성, 팀 상황 고려의 필요성, 실패를 빠르게 인정하는 용기까지.
지금은 멀티레포로 잘 운영하고 있지만, 미래에 팀 구조가 바뀌고 프로젝트가 커지면 다시 모노레포를 고려할 수도 있다. 그때는 이번 경험을 바탕으로 더 신중하게 접근할 것이다.
실패는 배움의 기회다. 이 경험이 다른 개발자들에게 도움이 되기를 바란다.