모노레포를 도입한 이유 (TurboRepo + Vercel)

유태승·2025년 4월 6일
post-thumbnail

❓ 프로젝트 설명

제가 만들 Pointer 프로젝트는 수학 문제와 다양한 해설을 통해 수험생에게 진단과 처방을 제공하는 서비스입니다.

이 프로젝트는 크게 두 영역으로 나뉩니다.

  • 문제와 해설을 등록하고 관리하는 관리자 페이지
  • 사용자가 문제를 풀고 해설을 확인하는 사용자 페이지

사용자 페이지의 SEO가 중요하므로 Next.js를 도입하기로 했습니다.


🎯 프로젝트 요구사항

기획 측에서는 사용자들이 사용하는 페이지와 관리자 페이지가 명확히 분리되도록,
두 페이지에 서로 다른 도메인을 적용하길 원했습니다.

페이지별로 다른 도메인을 적용하기 위해선 다음과 같은 방법들이 있었습니다.

1. 멀티레포

가장 먼저 떠오른 방법은 두 페이지를 서로 다른 Git 레포지토리로 완전히 분리하는 것이었습니다. 구조적으로 단순하고 명확하지만, 다음과 같은 문제점이 있었습니다.

  • UI 컴포넌트를 공유하기 어려움
  • API 서버는 1개이지만, API 클라이언트를 공통으로 사용할 수 없음.
  • 협업 시 코드 히스토리나 PR이 분산됨

결국 1개의 서비스이기 때문에 공통적인 부분이 많은데, 이를 효율적으로 관리할 수 없게되는 문제가 있습니다.

2. 리버스 프록시

EC2 등으로 배포한다면 Nginx에 리버스 프록시 설정을 통해 도메인에 따라 각각 다른 페이지로 라우팅할 수 있습니다.

하지만 Pointer 프로젝트는 Vercel로 배포하고 있기 때문에, 리버스 프록시 설정은 현실적으로 어려운 상태였습니다.

3. Next.js 미들웨어 분기

Next.js의 Middleware 기능을 활용하면 req.headers.host를 기준으로 도메인에 따른 라우팅 분기가 가능합니다.

하지만 이 방법은 아래와 같은 문제가 있었습니다.

  • 한개의 프로젝트가 되기 때문에 한쪽 코드만 수정해도 전체 재배포가 필요
  • 관리자와 사용자 페이지의 인증 방식이 다를 가능성이 큼
    (관리자 페이지는 id/pwd 로그인, 사용자 페이지는 소셜 로그인)

이러한 이유들로, 관리자 사용자 페이지를 다른 프로젝트로 분리해서 개발하기로 했습니다.


🕋 프로젝트 구조

그리고 어차피 다른 프로젝트로 만들거라면, SEO가 필요없는 관리자 페이지는 더 익숙한 React를 사용하기로 하였습니다.

하지만 이렇게 프로젝트가 물리적으로 나누어졌지만, 몇가지 문제가 있었습니다.

  • 서비스 관점에서 두 프로젝트를 완전 관련없는 프로젝트로 보기는 어려움
  • API 서버는 하나이고, 사용자와 관리자 모두 같은 API 클라이언트를 사용할 수 있음
  • 두 페이지 모두 웹 기반이라서 공통 UI 컴포넌트가 생길 가능성이 높았음

이러한 상황을 종합적으로 고려해, 두 프로젝트를 모노레포(monorepo)로 구성하기로 하였습니다.

  • API 클라이언트, UI 등 공유할 수 있는 코드는 공유
  • 다른 프로젝트이므로 각각 다른 도메인 연결 가능
  • 배포는 앱 단위로 독립적으로 관리

모노레포 구조는 서로 다른 앱의 독립성을 보장하면서도,
공통 코드의 중복 없이 효율적으로 관리할 수 있는 구조라고 판단했습니다.


🚀 프로젝트 배포

프로젝트는 Vercel로 배포할 계획이었기 때문에, Vercel에서 공식적으로 지원하고 있는 Turborepo를 도입하면 모노레포 구성부터 배포까지의 흐름을 간편하게 관리할 수 있을 것이라 판단했습니다.

Turborepo는 Vercel에 최적화된 모노레포 관리 도구로

  • 앱별로 독립적인 빌드 및 배포가 가능하고,
  • 캐싱을 통한 빠른 빌드 성능,
  • 공통 패키지 관리의 효율성 등
    모노레포의 빌드, 테스트, 배포 작업을 효율적으로 할 수 있게 해줍니다.

또한, Vercel과의 통합도 지원하므로 CI/CD 설정도 간단하게 구성할 수 있었습니다.

Turborepo 생성

Turborepo의 공식문서를 참고하며 모노레포 구조를 생성하고,
admin (React) service (Next) 두개의 프로젝트를 만들어주었습니다.

Vercel 배포

Vercel에서 새로운 프로젝트 추가해주겠습니다.

Turborepo로 생성한 것을 인식하고 Trubo 라는 라벨도 붙여줍니다.

모노레포라고 해서 통째로 배포할 수 있는 것은 아니고, 프로젝트 별로 배포를 해줘야합니다.

Root Directory를 선택하는 부분에서 어떤 프로젝트를 배포할 것인지 선택 해줍니다.

/apps 안에 admin(관리자) service(사용자) 가 있는 것을 볼 수 있고, Vite, Next 프로젝트라는 것도 알려줍니다.

이 과정을 2번 반복하며 각 프로젝트를 배포해주면 됩니다.

변경사항 있을때만 배포하기

Vercel은 기본적으로 연결된 프로젝트에 변경이 발생하면 자동으로 재배포를 진행합니다.
하지만 모노레포에서는 여러개의 프로젝트가 하나의 브랜치에 존재하기 때문에,
한쪽만 수정해도 모든 프로젝트가 함께 재배포되는 비효율적인 작업이 발생할 수 있습니다.

이를 방지하기 위해, Vercel은 “변경되지 않은 프로젝트는 빌드를 건너뛰는 기능”을 제공합니다.

Vercel은 아래 조건 중 하나라도 해당되면 프로젝트가 변경된 것으로 간주합니다

  • 해당 프로젝트의 소스 코드가 변경된 경우
  • 해당 프로젝트가 의존하고 있는 내부 패키지(예: 공통 라이브러리 등)에 변경이 생긴 경우
  • 패키지 매니저의 lockfile이 변경되었고, 그 영향이 해당 프로젝트의 의존성에 반영되는 경우

프로젝트 -> Settings -> Build and Deployment 에 들어가면

Root Directory 영역에 Skip deployments ~ 라고 되어있는 토글 버튼이 있습니다.
이 옵션을 활성화하면 해당 프로젝트에 영향이 없는 커밋일 경우 배포가 자동으로 건너뛰어집니다.
처음에 이 간단한 설정을 못찾아서 별의별 짓을 다해봤습니다...

모노레포의 공통 패키지에서 수정이 일어날 경우에는 해당 변경을 사용하는 모든 프로젝트가 함께 재배포됩니다.

배포 상태 확인하기

배포 페이지에서 우측에 Status 필터에서 canceled도 추가해주면 cancel된 배포들도 확인할 수 있습니다.

최근 서비스 페이지만 수정한 작업에서는 관리자 페이지 배포가 일어나지 않은 것을 확인할 수 있습니다.

공식문서에 따르면 이 기능을 이용할 경우 빌드 슬롯을 점유하지 않기 때문에, 빌드 대기 시간도 줄여주는 장점도 있다고 합니다.


🗂️ 배포환경 분리

기획 측의 요구로 QA 등을 진행할 수 있는 별도의 개발 환경이 필요했고,
API 서버도 이미 proddev로 분리되어 있는 상황이었습니다.

Vercel은 하나의 프로젝트 안에서 브랜치별로 다른 배포 환경(Preview, Production 등)을 구성할 수 있는 기능을 제공합니다.
또한, 각 환경에 맞는 환경 변수 설정과 도메인 연결도 가능하여 실제 운영과 유사한 환경을 쉽게 구성할 수 있습니다.

프로젝트 세팅 -> Environments에 들어가서 Preview에 들어가서

Branch Tracking 옵션을 활성화하면, 지정한 브랜치(ex. develop)로 커밋 시 자동으로 Preview 환경이 배포됩니다.
하단에서는 Preview 환경 전용 커스텀 도메인도 연결할 수 있습니다.

배포 환경별로 서로 다른 환경변수를 설정할 수 있어,
Preview 환경에서는 dev API 서버를,
Production 환경에서는 prod API 서버와 통신하게 설정할 수 있습니다.

문제는...

이 모든 설정을 마친 뒤에야 알게 되었는데,
브랜치별 Preview 환경 구성은 Vercel의 Pro 요금제 이상에서만 지원되는 기능이었습니다.🥲

결국 어쩔 수 없이 개발 환경에 대해 추가로 프로젝트를 등록해야 했습니다.

😭

이렇게 프로젝트를 분리함으로써 프로젝트의 개수는 많아졌지만, 무료 요금제 내에서도 모노레포의 모든 프로젝트를 운영/개발 환경을 분리하여 배포할 수 있었습니다.

참고자료

profile
FE Developer

0개의 댓글