오늘은 모노레포(Monorepo) 관리에 대해 이야기해볼게. 요즘 채용 공고나 실무 기술 스택을 보면 모노레포 경험을 요구하는 곳이 정말 많아졌거든. 내가 15년 동안 풀스택 개발자로 일하면서 여러 개의 저장소(Polyrepo)를 운영할 때 겪었던 가장 큰 고통이 바로 '의존성 지옥'과 '코드 중복'이었는데, 모노레포는 이 문제를 아주 우아하게 해결해 주더라고. 하지만 제대로 관리하지 못하면 오히려 거대한 쓰레기통이 될 수 있으니 실무에서 반드시 알아야 할 핵심 관리법을 공유해 줄게.
1. 패키지 매니저의 워크스페이스(Workspace)로 시작하기
모노레포를 도입한다고 해서 처음부터 거창하고 복잡한 도구를 가져올 필요는 전혀 없어. 기본은 패키지 매니저가 제공하는 워크스페이스 기능을 이해하는 것부터 시작하거든. 요즘 실무에서는 pnpm 워크스페이스가 사실상 표준(De facto standard)으로 자리 잡았어.
- 디스크 공간 절약:
pnpm은 하드 링크를 사용해서 동일한 패키지를 여러 프로젝트가 공유할 때 디스크 공간을 획득하고 설치 속도를 획기적으로 줄여줘. - 싱글 락파일(Lockfile): 모노레포 전체에서 단 하나의
pnpm-lock.yaml파일만 관리해야 해. 각 패키지마다 락파일이 따로 놀면 의존성 버전이 꼬여서 런타임 에러가 발생하기 쉽거든. - 가벼운 시작:
npm이나yarn도 자체 워크스페이스를 지원하니까, 처음에는 루트package.json에workspaces필드를 선언하는 것부터 차근차근 연습해 봐.
2. "전부 빌드하기"는 금물, Turborepo를 통한 빌드 최적화
모노레포를 운영할 때 흔히 저지르는 안티패턴이 바로 코드 한 줄 고쳤는데 저장소 전체를 다시 빌드하는 거야. 프로젝트가 20~30개로 늘어나면 CI/CD 빌드 시간만 몇 시간이 걸릴 수도 있거든. 그래서 우리는 빌드 시스템인 **Turborepo**나 Nx 같은 도구를 함께 사용해야 해.
- 캐싱(Caching) 활용: 이미 빌드된 결과물은 캐시해 두고, 변경 사항이 없는 패키지는 빌드 과정을 건너뛰게 설정해야 해.
- 필터링(
--filter)과 변경 감지:turbo run build --filter=...옵션을 사용하면 변경된 패키지와 그 패키지에 의존하는 녀석들만 똑똑하게 골라서 빌드할 수 있어. 최근에는 CI 환경에서--affected옵션으로 PR 보낸 브랜치의 변경 사항만 타겟팅해서 빌드 시간을 극적으로 줄이더라.
3. 환경 변수와 데이터베이스 마이그레이션 관리
여러 서비스가 하나의 저장소에 모여 있다 보니 환경 변수 관리와 데이터베이스 마이그레이션에서 실수가 자주 발생해.
turbo.json에 환경 변수 등록:Turborepo는 빌드 시점에 환경 변수를 캐시 키에 포함시켜야 해. 그렇지 않으면 개발 환경의 환경 변수가 프로덕션 빌드에 잘못 캐싱되어 들어가는 대참사가 발생할 수 있거든.- 마이그레이션 소유권 단일화: 여러 서비스가 하나의 데이터베이스를 공유하는 구조라면, 마이그레이션을 실행하는 주체(Owner)를 단 하나의 서비스나 패키지로 지정해 둬야 해. 배포 시점에 여러 서비스가 동시에 마이그레이션을 실행하면 레이스 컨디션(Race Condition)이 발생하니까 주의해야 해.
💡 핵심 정리
- **
pnpm workspaces**를 사용해 루트 단일 락파일로 의존성을 엄격하게 관리하자.- **
Turborepo**의 캐싱과 필터링 기능을 도입해서 불필요한 전체 빌드를 방지하자.- 환경 변수 노출과 DB 마이그레이션은 단일 소유권 규칙을 정해 안전하게 제어하자. 모노레포는 단순히 코드를 한곳에 모으는 기술이 아니라, 팀의 협업 생산성을 극대화하는 문화에 가까워. 처음부터 너무 완벽한 아키텍처를 만들려고 욕심내지 말고, 작은 토이 프로젝트에
pnpm과Turborepo를 얹어서 직접 빌드하고 배포해보는 경험을 꼭 쌓아봐. 이 경험 하나가 포트폴리오에서 너를 다른 지원자들과 완전히 차별화해 줄 거야.