“로컬에서는 잘 되는데 Vercel에 올리면 깨진다”는 말은 막연해 보이지만, 실제 원인은 대개 몇 가지 반복 패턴 안에 들어갑니다.
가장 빨리 푸는 방법은 배포 실패를 전부 같은 문제로 보지 않는 것입니다. 먼저 어디서 실패하는지부터 나눠야 합니다.
- 빌드 단계 실패
- 런타임 단계 실패
- 정적 자산이나 라우팅 문제
- 도메인이나 DNS 문제
이 글은 그 구분부터 빠르게 하는 실전 체크리스트입니다.
먼저 실패 유형부터 나누기
코드를 바로 고치기 전에 먼저 확인할 질문은 하나입니다. “빌드 자체가 실패했는가, 아니면 빌드는 성공했는데 배포 후 깨지는가?”
이 구분이 중요한 이유는 원인 후보가 완전히 달라지기 때문입니다.
- 빌드 실패는 환경 변수, Node 버전 차이, 의존성 분류, 프레임워크 설정 문제인 경우가 많습니다.
- 런타임 실패는 서버 전용 코드 유입, API 시크릿 누락, 실행 환경 가정 오류, 외부 서비스 장애인 경우가 많습니다.
- 도메인 실패는 앱 코드보다 DNS, SSL, 전파 상태 문제일 가능성이 높습니다.
이걸 구분하지 않으면 같은 가설로 재배포만 반복하게 됩니다.
환경 변수부터 확인하기
로컬 성공이 배포 실패로 바뀌는 가장 흔한 이유는 여전히 환경 변수입니다.
로컬의 .env.local 값은 자동으로 Vercel에 올라가지 않습니다. 또 preview와 production 값이 다를 수도 있습니다.
확인할 것:
Settings -> Environment Variables에 필요한 값이 모두 있는지- 올바른 환경에 값이 들어갔는지
- 코드가 정확한 변수명을 읽고 있는지
- 공개 가능한 클라이언트 변수는 프레임워크 규칙에 맞는 prefix를 쓰는지
개발 머신에 이미 값이 있어서 로컬에서는 문제를 숨기고 있을 수 있습니다.
Node와 패키지 매니저 버전 비교하기
같은 저장소라도 실행 환경 가정이 다르면 배포는 실패할 수 있습니다.
확인 포인트:
- 로컬 Node 버전
- Vercel Node 버전
- lockfile 상태
- 패키지 매니저 버전
특히 이런 경우에 자주 드러납니다.
- 의존성이 더 최신 런타임 기능을 기대할 때
- lockfile이 다른 버전에서 생성됐을 때
- 네이티브 패키지 동작이 환경마다 다를 때
의존성 관련 오류가 애매하게 보이면 먼저 버전 드리프트부터 제거하는 게 좋습니다.
런타임 패키지가 devDependencies에 들어가 있지 않은지 확인하기
로컬에서는 다 설치돼 있으니 괜찮아 보이지만, 배포 환경은 필요한 것만 기대하는 방식으로 동작합니다.
실제로 실행이나 빌드에 필요한 패키지가 개발 전용으로 잘못 분류돼 있으면 배포에서만 터질 수 있습니다.
대표 예시:
- 프레임워크 adapter
- 빌드 과정에서 실제로 쓰이는 markdown 또는 content 처리 패키지
- 인증, 스토리지, DB 관련 SDK
설치 후 실행에 필요하거나 빌드에 직접 필요하다면 개발 편의 도구처럼 취급하면 안 됩니다.
파일 경로 대소문자 문제 보기
이 문제는 어떤 환경에서는 조용히 지나가고, 어떤 환경에서는 바로 실패합니다.
예를 들어 Component.tsx 파일을 두고 import는 component.tsx처럼 쓰면 로컬에서는 지나가도 Linux 기반 환경에서는 깨질 수 있습니다.
확인할 것:
- 컴포넌트 import 대소문자
- asset 파일명
- route 파일명
- markdown/frontmatter 이미지 경로
이건 “로컬에선 되는데 운영에서만 안 되는” 대표 패턴입니다.
브라우저 코드와 서버 전용 코드를 분리하기
클라이언트 번들에 서버 전용 코드가 섞이면 배포가 실패하거나 런타임에서 깨질 수 있습니다.
대표 신호:
- 브라우저 코드에서
process.env직접 사용 - 공유 유틸에
fs,path같은 Node 전용 모듈 포함 - 클라이언트까지 내려가는 컴포넌트에서 서버 시크릿 참조
지원되지 않는 모듈이나 client bundle 오류가 보이면, 다른 설정보다 import graph부터 확인하는 게 빠릅니다.
asset 경로와 출력 구조 가정 다시 보기
정적 자산 문제는 처음엔 라우팅 문제처럼 보이기도 합니다.
살펴볼 것:
- markdown 내부 상대 경로
- 로컬 디렉터리 구조를 가정한 이미지 참조
- 하드코딩된 출력 경로
- 생성된 asset의 base path 가정
로컬 preview가 멀쩡하다고 해서 운영에서 같은 경로로 해석된다는 뜻은 아닙니다.
빌드 중 외부 API 호출은 실패 지점이 될 수 있습니다
정적 빌드가 외부 API에 의존하면, 배포 품질도 그 외부 시스템 상태에 묶입니다.
다음 이유로 실패할 수 있습니다.
- API가 느리거나 다운됨
- rate limit 도달
- 응답 스키마 변경
- Vercel에 필요한 자격 증명이 없음
빌드 타임에 원격 데이터를 가져온다면, 프레임워크를 의심하기 전에 그 요청 자체가 실패했는지부터 봐야 합니다.
프레임워크 출력 모드와 플랫폼 가정 확인하기
Vercel 배포 실패는 플랫폼 버그보다 설정 불일치인 경우가 더 많습니다.
확인할 것:
- static과 server 출력 모드가 맞는지
- adapter나 배포 타깃이 맞는지
- 지원되지 않는 런타임 가정이 없는지
- 출력 디렉터리나 라우팅 가정을 잘못 두지 않았는지
Astro, Next.js, Vite 계열을 오가면서 호스팅 모델도 비슷할 것이라 가정하면 여기서 자주 틀어집니다.
빌드가 성공했다면 런타임 로그로 넘어가기
빌드 성공은 앱 정상과 다릅니다.
배포는 됐는데 사이트가 깨지면 다음 순서로 봅니다.
- runtime 또는 function 로그 확인
- preview와 production 시크릿 비교
- 외부 서비스 접근 가능 여부 확인
- 로컬 파일 시스템 가정이 코드에 없는지 확인
이 시점부터는 build log보다 request 시점 오류가 더 중요합니다.
도메인 문제와 앱 문제를 분리하기
앱은 멀쩡한데 커스텀 도메인만 깨져 보이는 경우도 많습니다.
확인 포인트:
- DNS 레코드
- SSL 인증서 상태
- 전파가 아직 끝나지 않았는지
- 도메인이 올바른 프로젝트에 연결돼 있는지
배포 URL은 열리는데 커스텀 도메인만 안 되면, 그건 더 이상 앱 코드 문제가 아닙니다.
실전 점검 순서
시간이 없을 때는 이 순서가 가장 효율적입니다.
- 빌드 실패인지 런타임 실패인지 도메인 문제인지 먼저 구분
- 재배포 전에 로그를 한 번 정확히 읽기
- env와 런타임 버전 비교
- import, 의존성, 경로 대소문자 확인
- 외부 API와 출력 모드 확인
여러 군데를 한꺼번에 바꾸고 다시 배포하는 것보다 훨씬 빠릅니다.
빠른 체크리스트
- 실패 유형을 먼저 구분했다
- 필요한 환경 변수가 올바른 Vercel 환경에 존재한다
- Node와 패키지 매니저 버전이 맞는다
- 필요한 패키지가
devDependencies에 숨어 있지 않다 - import와 asset 경로 대소문자가 정확하다
- 서버 전용 코드가 클라이언트로 새지 않는다
- 빌드 중 호출하는 외부 API가 안정적이다
- 빌드 성공 후에는 런타임 로그를 확인했다
- DNS와 SSL을 앱 문제와 분리해서 봤다
FAQ
Q. 제일 먼저 뭘 봐야 하나요?
실패 유형을 먼저 나누고, 그 다음 로그와 환경 변수를 확인하세요.
Q. 왜 로컬 빌드는 되는데 배포는 실패하나요?
대부분은 production 환경 변수 누락, 버전 차이, 경로 대소문자, 의존성 분류, 서버 전용 코드 유입 때문입니다.
Q. 배포는 성공했는데 사이트가 안 열리면요?
런타임 로그를 먼저 보고, 그 다음 커스텀 도메인, DNS, SSL 상태를 확인하세요.
Read Next
- 배포 전체 흐름이 먼저 필요하면 Vercel Deployment Guide를 먼저 보세요.
- 문제가 배포보다 도메인 쪽이라면 Cloudflare DNS Guide가 다음 글입니다.
Related Posts
심사 대기 중에는 광고 대신 관련 가이드를 먼저 보여줍니다.
먼저 읽어볼 가이드
검색 유입이 많은 핵심 글부터 이어서 보세요.
- 미들웨어 트러블슈팅 가이드: Redis vs RabbitMQ vs Kafka 개발자를 위한 미들웨어 트러블슈팅 허브 글입니다. Redis, RabbitMQ, Kafka 중 어떤 증상부터 먼저 봐야 하는지와 어떤 문제 패턴이 각 시스템에 가까운지 정리합니다.
- Kubernetes CrashLoopBackOff: 먼저 볼 것들 startup failure, probe, config, resource limit 관점에서 CrashLoopBackOff를 어떻게 나눠서 봐야 하는지 정리한 가이드입니다.
- Kafka consumer lag가 계속 늘 때: 트러블슈팅 가이드 Kafka consumer lag가 계속 늘어날 때 무엇부터 봐야 하는지 정리합니다. poll 주기, 처리 속도, rebalance, consumer 설정까지 실전 기준으로 다룹니다.
- Kafka Rebalancing Too Often 가이드 Kafka consumer group에서 rebalance가 너무 자주 일어날 때 membership flapping, poll timing, protocol, assignment churn을 어떤 순서로 봐야 하는지 설명하는 실전 가이드입니다.
- Docker container가 계속 재시작될 때: 먼저 확인할 것들 exit code, command failure, environment mistake, health check 관점에서 Docker restart loop를 푸는 실전 가이드입니다.
심사 대기 중에는 광고 대신 관련 가이드를 먼저 보여줍니다.