배경 설명
뜨도록 프로젝트 처음 셋팅 시 프론트 개발자분이 next를 선택하셨고, 익숙하게 vercel hobby플랜에 public repo로 연결하여 배포해주시던 상황이었다.
하지만 프로젝트를 진행하면서 해당 repo를 private으로 돌려야할 일이 발생해 CLI + GitHub Actions 방식으로 갈아타게 되었다.
같은 상황의 소규모 프로젝트(특히 모노레포)에게 도움 되길 바라며 삽질 과정을 남긴다.
Vercel 쪽 준비
현재 프론트쪽은 모노레포 구조에 2개의 프로젝트로 구성되어있다.
각각 따로 배포되어야 하므로 프로젝트를 2개 생성해 진행한다.
| 할 일 | 실전 메모 |
|---|---|
| 프로젝트 2개 생성 | dddorok-web, dddorok-admin (모노레포라 app 디렉터리별 분리) |
| GitHub 연동 끊기 | Settings ▸ Git ▸ Disconnect – 깔끔하게 연결 해제 |
| Personal Token 발급 | Profile ▸ Settings ▸ Tokens → VERCEL_TOKEN 으로 GitHub Secret 등록 |
| Root Directory 지정 | 대시보드 Settings ▸ Build and Deploymentapps/web, apps/admin 입력 후 Include files outside… 토글 ON |
토글 ON 을 켜두면 설정한 루트의 바깥쪽 파일, 즉
package.json,pnpm-lock.yaml등을 같이 가져가 빌드에서 의존성 누락을 방지한다.
Vercel CLI로 프로젝트 연결 & 첫 배포
1. 아직 CLI를 안 깔았다면:
npm i -g vercel2. 로그인 (한 번만)
vercel login # 이메일 인증링크 클릭
깃허브 연동 되어있어 github 선택

3. 프로젝트 루트에서 링크
cd <프론트엔드 레포>
vercel link # 질문 3개:
# ① 어떤 스코프(team/personal)? → 선택
# ② Existing 프로젝트 찾을 건지? → Yes
# ③ 목록에서 dddorok-frontend-web 선택
내경우 팀 선택 후 프로젝트가 보이지 않아
dddorok-web를 수동으로 입력해 주었다.
.vercel/project.json 에 orgId, projectId 가 자동 저장된다.
4. 로컬에서 첫 배포(선택)
vercel --prod # 1회 배포해두면 대시보드에 Production 카드 생성
CLI 배포는 내부에서 같은 vercel --prod --token … 명령을 쓰기 때문에,
GitHub Action 이 호출할 로직을 미리 테스트하는 셈.

Gibhub Action & Workflow
Secret 준비

| 시크릿 이름 | 값 | 비고 |
|---|---|---|
| VERCEL_TOKEN | Vercel 대시보드에서 발급한 Personal Token | 팀 Owner 계정으로 발급한 토큰을 그대로 사용 |
| VERCEL_ORG_ID | .vercel/project.json의 orgId | 웹 앱 및 어드민 |
| VERCEL_PROJECT_ID_WEB | 같은 파일의 projectId | 웹 앱 전용 |
| VERCEL_PROJECT_ID_ADMIN | projectId | 어드민 전용 |
두 프로젝트 모두 같은 팀(Org)소속이라 VERCEL_ORG_ID 하나만 등록하였다.
추후 QA → Staging → Prod 등 한 액션에서 여러 프로젝트에 연속 배포할 때vercel deploy --prod --project $QA_ID,--project $PROD_ID식으로 두 번 호출해도 구조 그대로 사용 가능
Workflow 작성 (deploy.yaml)
워크플로우 작성 내용:
- ➖ workflow_dispatch : web/admin/all 선택형 수동배포
- ➖ push@development : 디렉터리 변경 감지 후 자동배포
- ➖ dorny/paths-filter : apps/web/, apps/admin/ 만 체크
- ➖ vercel pull → build --prod → deploy --prebuilt
- ➖ Slack Webhook 로 성공 / 실패 알림
루트 디렉터리 삽질 포인트
| 삽질 | 증상 / 오류 | 해결 |
|---|---|---|
| CLI 를 apps/web 에서 실행 | vercel build → 또다시 apps/web/apps/web 경로 탐색 → 빌드 실패 | 루트에서 실행 하되 .vercel/project.json 의 "rootDirectory": "apps/web" 값으로 빌드 경로가 자동 보정된다. |
| Include files outside… OFF | 빌드 단계에서 모노레포 최상단 pnpm-workspace.yaml 를 못 찾아 의존성 오류 | 토글 ON 으로 해결 |
| --cwd apps/web 강제 지정 | Pre-built 결과는 ok인데 vercel deploy . 시 정적 파일 경로가 꼬임 | rootDirectory 가 이미 있으므로 --cwd 옵션은 사용하지 않는다. |
각 스텝 및 vercel 명령어의 실행 위치 (이것만 자세히 알고있어도 삽질포인트가 줄어든다 🥲)
Key Point:
GitHub Actions 의 step 위치 ↔ Vercel CLI 의 rootDirectory ↔ UI Root Directory_ 설정이 모두 일치해야 삽질을 피한다.
| 구분 | 작동기준 디렉터리 | 핵심 인자·플래그 | 이중 중첩/주의 포인트 |
|---|---|---|---|
1. checkout actions/checkout@v4 |
레포 루트 | (없음) | 이후 모든 step 의 기준점 |
2. pnpm install |
레포 루트 | --frozen-lockfile |
모노레포 루트의 pnpm-workspace.yaml 필수 |
3. vercel pull |
레포 루트 | --environment=production --yes --token=$VERCEL_TOKEN |
.vercel/project.json의 "rootDirectory": "apps/web" 확인 후 apps/web 안으로 env 파일 다운로드 |
4. vercel build |
레포 루트 → 자동 apps/web | --prod --token=… |
.vercel/project.json의 rootDirectory 읽고 내부적으로 디렉터리 이동 → apps/web/.vercel/output 생성 |
5. vercel deploy |
레포 루트 | --prebuilt --prod --yes --token=… |
이미 빌드된 .vercel/output 그대로 업로드 → 추가 cd 필요 없음 ❌ cd apps/web 하거나 --cwd apps/web 주면 **apps/web/apps/web** 이중 중첩 발생 |
| 6. Slack 알림 | 레포 루트 | (curl, jq) | 빌드 산출물과 경로 무관 |
🛠️ 내 상황 & 해결 과정
1. 초기 세팅
- Vercel 프로젝트의 Root Directory 를
/(루트)로 그대로 뒀다. - “큰일 없겠지?” 싶었지만, 모노레포라 빌드 경로가 계속 꼬이기 시작…
2. 온갖cwd·상대/절대경로 삽질 cd apps/web,vercel build --cwd …,vercel deploy ./apps/web등 시도- 결과는 apps/web/apps/web 같은 이중 중첩 & 정적 파일 404 파티 🤯
3. Root Directory를apps/web으로 수정 - Vercel 대시보드 → Settings ▸ General → Root Directory 필드에
apps/web입력
4. 최종 워크플로 수정 → 정상 작동
- run: npx vercel pull --yes --environment=production --token="$VERCEL_TOKEN"
- run: |
npx vercel build --prod --token="$VERCEL_TOKEN"
ls -al .vercel/output
# Deploy
- id: deploy
run: |
DEPLOY_URL=$(npx vercel deploy . --prebuilt --prod --yes --token="$VERCEL_TOKEN" | tail -1)
echo "url=$DEPLOY_URL" >> "$GITHUB_OUTPUT"
✅ 마무리 – 루트 디렉터리 일관성의 교훈
- - rootDirectory 값을 딱 한 곳(Vercel UI)에서만 정의하고,
CLI·GitHub Actions 모두 레포 루트(.) 기준으로만 동작하게 만들면
(1) 빌드 캐시가 한 군데에 쌓이고, (2) 경로 관련 버그가 싹 사라진다.
- - 반대로 UI·CLI·Action 중 하나라도 서로 다른 디렉터리를 바라보면?
- 1. Vercel 빌드는
apps/web으로, - 2. CLI 는
apps/web/apps/web으로, - 3. Next.js 로더는 또 상대경로가 어긋나서
정적 자산 404 → ISR 오류 → 배포 실패의 무한 루프가 시작된다.
- 1. Vercel 빌드는
- -나도 처음엔 “그냥
cd해서 빌드하면 되겠지?” 싶어 몇 시간 동안
apps/web/apps/web/apps/web… 로 진입하거나 파일을 찾을 수 없다는 로그를 구경했다....
- - 해결책은 단순하다.
- 1) UI에서 rootDirectory 지정 → 2) Include files outside… ON →
- 3) 모든 CLI 호출은
<path> = ..
이렇게 3단계만 지키면 모노레포 + Private Repo + Hobby 플랜 조합도
스무스하게 돌아간다.
“rootDirectory를 UI·CLI·Action 세 군데 중 하나라도 다르게 쓰면,
빌드 로그가 아닌 ‘미궁 속 중첩 디렉터리’와 씨름하게 된다(맞출 생각은 크게 하지말자). – 내가 다 해봤다 😇”
'devops' 카테고리의 다른 글
| [GitHub Actions으로 AWS환경에 배포] EC2 SSH 접속 → Docker 이미지 전송 → 슬랙 알림까지 (7) | 2025.05.22 |
|---|