본문 바로가기
개발자/기술스택 도구

모노레포 도입 후 실제 팀에 생긴 변화

by 나무011 2026. 7. 17.
개발자 현직자 솔직 경험담

모노레포 도입 후
실제 팀에 생긴 변화

Turborepo로 전환한 지 6개월, 좋아진 것과 예상 못 한 문제들

Frontend Developer 2026년 6월 약 14분 읽기

모노레포를 도입하기로 한 이유

우리 팀 상황을 먼저 설명한다. 프론트엔드 개발자 셋이서 세 개의 Next.js 프로젝트를 유지하고 있었다. 사용자용 웹 서비스, 어드민 패널, 그리고 마케팅 랜딩페이지. 세 레포지토리가 따로 있었다.

문제는 공통 컴포넌트였다. 버튼, 인풋, 모달 같은 UI 컴포넌트를 세 레포가 각자 갖고 있었다. 디자인 시스템 변경이 있으면 세 곳을 각각 고쳐야 했다. 색상 토큰 하나 바꾸는 데 PR이 세 개였다. ESLint 설정, TypeScript 설정, Prettier — 전부 따로따로 버전이 달랐고, 어드민은 이미 낡은 eslint-config를 쓰고 있었다.

결정적으로 어드민과 메인 웹이 공유하는 유틸 함수가 생겼는데, 한 쪽을 수정하면 다른 쪽에 복사해서 붙여넣어야 했다. 그 순간이었다. "이건 진짜 안 되겠다."

모노레포 도입 후 실제 팀에 생긴 변화
모노레포 도입 후 실제 팀에 생긴 변화
⚠️ 도입 전 상황 요약

멀티레포 3개 운영, 공통 컴포넌트 중복 유지, 설정 파일 버전 제각각, 유틸 함수 copy-paste 동기화. 팀원 셋이서 실질적으로 아홉 개를 유지하는 것과 마찬가지였다.

어떤 구조로 설계했나

Turborepo를 선택했다. pnpm workspace와 함께 쓰는 구조로 잡았다. 패키지 구조를 정의하는 데 하루, 실제 마이그레이션에 2주 정도 걸렸다.

📁 모노레포 디렉토리 구조 (최종)
my-company/ ├── apps/ │ ├── web/ # 메인 서비스 (Next.js 14) │ ├── admin/ # 어드민 패널 (Next.js 14) │ └── landing/ # 마케팅 랜딩 (Next.js 14) ├── packages/ │ ├── ui/ # 공통 컴포넌트 (Button, Input, Modal...) │ ├── utils/ # 공통 유틸 함수 (날짜, 포맷, 검증) │ ├── types/ # 공통 TypeScript 타입 정의 │ └── config/ # ESLint, TS, Tailwind 공통 설정 ├── turbo.json ├── pnpm-workspace.yaml └── package.json
📄 turbo.json — 파이프라인 설정
{ "$schema": "https://turbo.build/schema.json", "pipeline": { "build": { "dependsOn": ["^build"], // 의존 패키지 먼저 빌드 "outputs": [".next/**", "dist/**"] }, "lint": { "dependsOn": ["^build"] }, "dev": { "cache": false, "persistent": true } } }

마이그레이션 2주 — 예상보다 험난했다

Day 1~2
레포 구조 설계 및 pnpm workspace 세팅

공통으로 뽑아낼 것들 목록화. packages/ui에 뭘 넣을지 팀원 셋이서 30분 논의했는데 생각보다 의견이 갈렸다. 결국 현재 세 앱이 실제로 공유하는 것만 넣고 나머지는 나중으로 미뤘다.

Day 3~5
packages/config 분리 — 생각보다 까다로웠다

ESLint 설정을 공통 패키지로 빼는 과정에서 앱마다 다른 규칙이 충돌했다. 어드민은 오래된 eslint-plugin 버전을 쓰고 있었고, 공통 config를 맞추려면 어드민 전체 lint 오류를 다 잡아야 했다. 하루 반을 여기에만 썼다.

Day 6~9
packages/ui 컴포넌트 통합

세 앱의 Button 컴포넌트가 다 달랐다. props도 다르고, 스타일도 달랐다. 하나로 합치는 과정에서 어느 것을 기준으로 할지 결정이 필요했다. 결국 가장 완성도 높은 메인 웹 버전을 베이스로 하고, 어드민용 variant를 추가하는 방향으로 합의했다.

Day 10~12
CI/CD 파이프라인 재구성

GitHub Actions 워크플로우를 Turborepo의 affected 감지에 맞게 바꿨다. 변경된 패키지만 빌드·테스트하는 구조로. 처음엔 캐시 설정이 잘못돼서 전체 빌드가 계속 돌았다. turbo.json 설정을 세 번 고쳤다.

Day 13~14
스테이징 배포 및 QA

세 앱 전부 스테이징 배포. Vercel 프로젝트 설정을 각각 루트 디렉토리 기준으로 바꿔야 했다. landing 앱에서 packages/ui import 경로가 안 잡히는 오류가 마지막 날 나왔다. tsconfig paths 설정 문제였다.

🔴 마이그레이션 중 가장 힘들었던 것

기술적인 문제보다 결정의 연속이 힘들었다. "이 컴포넌트는 공통으로 뺄 만큼 범용적인가?", "이 props 이름은 직관적인가?" — 작은 결정들을 계속 내려야 했고, 셋이서 의견이 다를 때마다 논의 시간이 생겼다. 결정 피로가 컸다.

도입 후 6개월 — 수치로 본 변화

↓68% CI 빌드 시간 캐시 히트율 82%
1곳 디자인 수정 PR 기존 3곳 → 1곳
0건 설정 파일 불일치 ESLint, TS, Prettier
↓40% 코드 리뷰 시간 공통 컴포넌트 기준 통일

※ 팀 내부 측정 기준이며, CI 로그와 PR 통계를 기반으로 산출한 수치입니다.

항목별 체감 개선도 (팀원 3인 평균)
공통 코드 동기화
 
92%
빌드 속도
 
85%
코드 리뷰 효율
 
70%
온보딩 복잡도
 
↑악화
로컬 개발 환경
 
↑복잡

확실히 좋아진 것들

개선 1
디자인 토큰 변경이 한 번에 반영된다

도입 전 가장 고통스러웠던 작업 중 하나가 색상 업데이트였다. 디자이너가 primary 컬러를 바꾸면 세 레포에 각각 PR을 올리고, 각각 리뷰받고, 각각 배포해야 했다. 실수로 어드민만 안 바꾼 채 배포된 적도 있었다.

모노레포로 전환한 후 packages/config/tailwind에 색상 토큰이 하나만 있다. 바꾸면 세 앱에 전부 반영된다. PR 하나, 리뷰 한 번, 배포 한 번. 이것만으로도 도입 가치가 있었다.

 
 
 
도입 전 vs 도입 후 — 색상 토큰 변경 PR 수

# 도입 전

PR #241 — feat(web): update primary color to #1a73e8

PR #089 — feat(admin): update primary color to #1a73e8

PR #033 — feat(landing): update primary color to #1a73e8

→ 리뷰어 3명, 배포 3번, 실수 위험 3배


# 도입 후

PR #412 — feat(config): update primary color to #1a73e8

→ 리뷰어 1명, 배포 1번, 세 앱 동시 반영

개선 2
타입 정의를 한 곳에서 관리한다

User 타입이 세 곳에 있었다. 그런데 미묘하게 달랐다. 어드민의 User는 role 필드가 있었고, 메인 웹의 User는 없었다. API 응답 타입을 바꿀 때마다 어떤 앱이 어떤 타입을 쓰는지 확인하느라 시간이 걸렸다.

packages/types에 공통 타입을 정의하고 앱별 확장이 필요하면 extends해서 쓰는 방식으로 바꿨다. 이후로 "어드민에서 이 타입 구조 어떻게 됐더라"는 질문이 사라졌다. 한 파일만 보면 됐다.

개선 3
변경된 패키지만 CI가 돈다

멀티레포 시절엔 어느 레포든 커밋이 들어오면 그 레포 전체 CI가 돌았다. packages/ui의 버튼 하나 수정해도, 그 패키지를 의존하는 세 앱 전부 빌드됐다. 전체 빌드에 평균 12분이 걸렸다.

Turborepo의 캐싱 덕분에 바뀐 패키지와 그 영향받는 패키지만 다시 빌드한다. packages/utils 함수 하나 수정하면 utils만 빌드하고, 그걸 쓰는 앱들은 캐시에서 가져온다. 평균 CI 시간이 4분 이하로 줄었다.

예상 못 했던 문제들

좋은 점만 있었으면 이 글을 쓰지 않았다. 솔직하게 쓴다.

!
문제 1
새 팀원 온보딩이 훨씬 복잡해졌다

멀티레포 시절에 새 팀원이 오면 "이 레포 클론하고 npm install 하면 돼"였다. 모노레포 도입 후 처음 온보딩한 팀원이 로컬 세팅에만 반나절을 썼다. pnpm이 익숙하지 않았고, workspace 개념을 처음 봤고, 특정 앱만 dev 서버로 띄우는 방법을 몰랐다.

결국 온보딩 문서를 새로 썼다. 그게 없으면 혼자 세팅하기 어려운 구조가 됐다는 뜻이기도 하다. 좋아진 것과 복잡해진 것이 동시에 왔다.

!
문제 2
packages/ui 컴포넌트 변경이 세 앱에 동시에 영향을 준다

공유 컴포넌트의 양날의 검이다. Button 컴포넌트에서 size props 구조를 바꿨더니 세 앱에서 타입 오류가 동시에 터졌다. 멀티레포 시절엔 한 앱씩 순차적으로 업데이트할 수 있었는데, 모노레포에서는 한 번에 세 앱을 다 고쳐야 PR을 올릴 수 있었다.

Breaking change가 생기면 영향 범위가 한꺼번에 커진다. 컴포넌트 API를 바꿀 때 더 신중하게, 더 많은 시간을 써야 하게 됐다. 그게 좋은 건지 나쁜 건지는 아직도 모르겠다.

!
문제 3
IDE와 툴이 전부 무거워졌다

VS Code에서 루트 디렉토리로 열면 파일 트리가 방대해졌다. TypeScript language server가 node_modules를 포함한 전체 레포를 인덱싱하느라 처음 열 때 2~3분이 걸렸다. M2 MacBook Air 기준으로도 초기 로딩이 체감됐다.

해결책으로 앱별로 VS Code workspace를 따로 정의해서 쓰는 방법을 쓰고 있는데, 이것도 "그냥 클론해서 열면 되던" 시절에 비하면 한 단계 더 생긴 것이다. 편의성과 구조적 이득 사이에서 절충점을 찾아가는 중이다.

멀티레포 vs 모노레포 — 지금 생각하는 기준

기준 멀티레포에 유리 모노레포에 유리
팀 규모 소규모·독립팀 공유 많은 팀
공통 코드 비중 거의 없음 많음 (UI, utils)
배포 독립성 완전 독립 부분 독립
온보딩 난이도 낮음 높음
설정 관리 레포마다 따로 한 곳에서
Breaking change 영향 앱별 격리 전체 동시 영향
CI 효율 레포 단위 변경분만 실행
IDE 성능 가벼움 무거움

모노레포는 만능 해결책이 아니다. 공유하는 코드가 많고, 그 공유를 일관성 있게 유지하는 게 팀의 실질적인 병목일 때 효과가 나온다.

6개월 후 팀이 내린 결론

다시 선택하겠냐고 물으면, 우리 팀 상황에서는 그렇다고 할 것이다. 공통 컴포넌트 동기화에 쓰던 에너지가 확실히 줄었고, 설정 파일 불일치로 생기는 사소한 오류들이 없어졌다. 디자인 시스템 변경이 예전보다 훨씬 두렵지 않아졌다.

다만 팀 규모가 더 작거나, 세 앱이 독립적으로 돌아가는 구조였다면 굳이 했을까 싶다. 모노레포를 도입하기 전에 "우리가 얼마나 많은 코드를 실제로 공유하고 있는가"를 먼저 측정해보는 게 맞다. 그 비중이 낮다면 복잡도만 늘어나는 셈이다.

❌ 모노레포가 오히려 독이 될 때

팀마다 기술 스택이 다를 때 (React + Vue 혼용)

앱들이 공유하는 코드가 거의 없을 때

배포 주기와 릴리즈가 완전히 독립적일 때

팀이 작고 툴 셋업에 투자할 시간이 없을 때

✅ 모노레포가 진가를 발휘할 때

공통 UI 컴포넌트를 여러 앱이 공유할 때

설정 파일 버전 불일치가 반복 문제가 될 때

같은 유틸 함수를 copy-paste로 동기화 중일 때

CI 빌드 시간이 병목이 되고 있을 때

✅ 도입을 고려한다면

작게 시작하는 것을 권한다. 전체 마이그레이션을 한 번에 하지 말고, packages/config 하나만 먼저 빼보는 것부터 시작하면 좋다. 그 과정에서 우리 팀이 이 구조와 맞는지 체감해볼 수 있다. Turborepo 공식 문서의 getting-started가 생각보다 잘 되어 있어서 진입장벽이 낮다.


모노레포는 도구다. 도구가 팀을 이끄는 게 아니라, 팀의 문제가 도구를 결정해야 한다. 우리 팀에게는 맞는 선택이었고, 6개월이 지난 지금 그 판단은 바뀌지 않았다. 다만 더 일찍 온보딩 문서를 써뒀어야 했고, 컴포넌트 API 변경 프로세스를 미리 정해뒀어야 했다는 아쉬움은 있다.

💬 모노레포 도입을 고민 중이시거나, 이미 운영 중이신가요?

어떤 툴을 쓰셨는지, 도입 과정에서 가장 어려웠던 부분이 뭔지 댓글로 나눠주세요. Turborepo 외에 Nx를 쓰는 분들의 경험도 궁금합니다. 비교 경험이 있으시면 더욱 환영합니다.


소개 및 문의 · 개인정보처리방침 · 면책조항

© 2026 나무핀