Search

CMS 모노레포 개선기: 빌드 시간 단축부터 번들 최적화까지

URL
생성 일시
2026/04/24 00:06
최종 편집 일시
2026/04/24 00:06
태그
여기어때
파일과 미디어
|| 안녕하세요 여기어때컴퍼니 백오피스웹개발팀 기리입니다. 저희 팀은 여기어때 통합CMS를 관리하고 있습니다. 10여 개 Next.js 앱을 하나의 모노레포에서 운영하고 있는데, 배포할 때마다 약 14분을 기다려야 했습니다. 앱은 계속 추가되고 있었기 때문에, 손을 대지 않으면 배포 시간은 더 늘어날 수밖에 없었습니다. 코드 한 줄 수정하고 dev 환경에서 확인하려면 14분, 핫픽스도 14분. 하루에도 여러 번 배포하는 저희에게 이 대기 시간은 개발 생산성에 직접적인 영향을 주고 있었습니다. 이 글에서는 빌드 파이프라인을 분석하고, 배포 시간을 약 40% 단축한 과정을 정리해보았습니다. 통합CMS의 빌드 구조 저희 통합CMS는 아래와 같은 Spring Boot + Next.js가 결합된 구조로 되어있습니다. 간단히 설명하면, Spring Boot 서버가 인증/라우팅을 담당하고 프론트엔드 정적 파일을 Thymeleaf 템플릿으로 서빙하는 구조입니다. 정적 배포 구조이기 때문에 Next.js의 SSR은 사용할 수 없고, Static Export 모드로 빌드해야 합니다. // next.config.mjs (각 앱 공통 패턴) const nextConfig = { output: 'export', // 정적 HTML/JS/CSS만 생성 assetPrefix: '/js/service/app-name/', // Spring Boot 정적 리소스 경로 basePath: '/app-name', // Spring Boot 라우팅 경로 ... }; 빌드된 정적 파일은 빌드 후처리 스크립트를 통해 Thymeleaf 템플릿으로 변환되고, 사용자 인증·권한 정보가 주입됩니다. 현재 모노레포에는 10여 개 Next.js 앱과 공유 패키지(@packages/ui, @packages/service 등)가 있으며, 모든 앱의 빌드 결과물이 하나의 Spring Boot JAR에 포함됩니다. 배포 시 기존 빌드 파일을 전부 삭제하고 새로 복사하기 때문에, 프론트엔드 앱 하나만 수정하더라도 전체 앱을 빌드해야 합니다. 마이크로서비스로 분리하면 앱별 독립 배포가 가능하지만, 인증/권한 체계와 운영 인프라를 고려하면 현실적으로 쉽지 않은 선택이었습니다. 그래서 저희는 현재 아키텍처를 유지하면서 빌드 시간을 줄이는 방법을 찾아야 했습니다. 개선 전 상황: 왜 약 14분이 걸렸나빌드 파이프라인을 분석해 보니 병목은 명확했습니다. 이를 시각화하면 다음과 같습니다. 가장 큰 병목은 Next.js 빌드였습니다. 10여 개 앱을 하나씩 순서대로 빌드하고 있었고, TurboRepo의 concurrency가 1로 설정되어 있어 빌드 서버의 자원을 제대로 활용하지 못하는 상태였습니다. 개선 1: 빌드 환경 정비 빌드 환경부터 먼저 정리했습니다. .dockerignore를 강화하여 node_modules, .git, 테스트 파일, 빌드 산출물 등 빌드에 불필요한 파일을 제외했습니다. 빌드 환경으로 전송되는 파일이 줄어들면서 초기 준비 시간이 체감될 정도로 단축됐습니다. 또한 이전 빌드 이미지를 캐시로 재활용하도록 설정하여, 시스템 패키지 설치나 의존성 설치처럼 변경 빈도가 낮은 단계는 빌드를 건너뛸 수 있게 됐습니다. 개선 2: TurboRepo 병렬 빌드 + 자동 재시도 가장 큰 효과를 본 변경입니다. 10여 개 앱의 Next.js 빌드를 순차에서 병렬로 전환했습니다. 기존 순차 빌드와 병렬 빌드의 차이는 다음과 같습니다. TurboRepo 캐시 최적화 병렬 빌드와 함께, TurboRepo의 캐시 설정도 최적화했습니다. turbo.json에서 어떤 파일이 바뀌었을 때 다시 빌드할지(inputs), 빌드 결과물은 어디에 있는지(outputs)를 지정하면 TurboRepo가 변경 여부를 정확히 판단하여 불필요한 재빌드를 건너뜁니다. { "tasks": { "build": { "inputs"