TechFeedTechFeed
Programming Languages

Heap out of memory, Node.js 메모리, --max-old-space-size | 빌드가 137로 죽으면?

빌드 종료 코드 137은 문법 오류가 아니라 커널이 프로세스를 죽인 신호다. 힙 메시지와 러너 메모리를 같이 보고, 원본 이미지를 줄인 뒤 공식 힙 상한만 올린다. 한국 1인 개발자, Node.js, Next.js, 깃허브 액션, 도커, CI, 빌드 기준. 2026년 8월 Node.js와 Next.js, 깃허브 공식 문서.

by

빌드가 137로 끝나면 코드 문법 오류가 아니라, 프로세스가 메모리 한도에 걸려 커널이나 오케스트레이터에 죽은 겁니다. 노드로 치면 힙이 모자라면 JavaScript heap out of memory가 먼저 보이고, 그다음 강제 종료 코드 137이 따라옵니다.


next build가 로컬은 되고 CI 러너만 죽는 패턴을 1인 넥스트 사이트에서 여러 번 봤습니다. 이미지가 많거나 웹팩 캐시가 큰 날일수록 잘 납니다.


플래그부터 올리기 전에 힙 덤프와 러너 메모리, 이미지 최적 순서를 보세요. 근거는 Node.js --max-old-space-sizeNext.js 메모리에 있습니다.


종료 코드 137은 누가 죽였다는 뜻이다

128+9, 즉 SIGKILL을 받았다는 숫자입니다. 노드가 예외를 던지고 스스로 끝난 0이나 1과 다릅니다. 리눅스 OOM killer, 도커 메모리 한도, 깃허브 액션 러너 한도가 이 신호를 보냅니다.


힙 부족이면 그 전에 FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory가 로그에 남습니다. 137만 있고 힙 메시지가 없으면 다른 프로세스가 잡혔거나, 로그가 잘린 겁니다. CI 로그 전체를 내려받으세요.


윈도 작업 관리자에서 종료하면 숫자가 다릅니다. 이 글은 리눅스 CI·도커·버셀 빌드처럼 유닉스 종료 코드를 쓰는 칸만 봅니다.


먼저 기억할 것 | 137은 힙 플래그 한 줄로 끝나지 않습니다. 러너 RAM이 3GB인데 힙을 8GB로 올리면 같은 신호로 더 빨리 죽습니다. 한도와 플래그를 같이 보세요.


CI 러너 메모리 한도에 걸려 빌드 프로세스가 죽는 개념 이미지
힙 상한을 올려도 컨테이너 RAM이 더 작으면 137로 죽는다

힙 플래그와 러너 RAM을 같이 보기

플래그는 V8 구세대 힙 상한이고, 러너 RAM은 그 상한의 천장입니다.


무엇을 제한하나올리는 방법
V8 힙자바스크립트 객체 공간--max-old-space-size=4096
NODE_OPTIONS자식 노드에도 같은 플래그환경변수로 전달
러너/도커 RAM프로세스 전체 RSSlarger runner, mem_limit
스왑RAM을 넘긴 뒤 디스크느리고 OOM을 늦출 뿐
넥스트 빌드페이지·이미지 동시 처리실험적 메모리 옵션, 이미지 축소

공식 CLI는 메가바이트 정수입니다. 존재하지 않는 플래그를 넣지 마세요. NODE_OPTIONS=--max-old-space-size=4096는 npm 스크립트가 띄운 노드에도 전달됩니다.


깃허브 호스티드 러너는 당시 문서의 RAM을 따릅니다. 큰 모노레포면 larger runner나 셀프 호스티드가 필요합니다. 힙만 키우고 러너는 그대로면 137이 남습니다.


힙 상한을 환경변수로 주기
export NODE_OPTIONS=--max-old-space-size=4096 npx next build # package.json # "build": "NODE_OPTIONS=--max-old-space-size=4096 next build"

올리기 전에 빌드가 먹는 양을 줄이기

원본 이미지를 public에 통째로 두면 빌드가 한꺼번에 디코드합니다. 넥스트 이미지 최적화는 편리하지만 CI RAM을 많이 씁니다. 큰 PNG를 미리 줄이거나, 빌드 중 처리할 이미지 수를 나누세요.


소스맵을 프로덕션 빌드에서 켜 두면 힙이 늘어납니다. 디버그가 끝나면 끕니다. 웹팩 캐시가 깨진 채 커지면 한 번 .next를 지우고 다시 빌드해 보세요. 로컬 캐시가 CI에 없으면 CI만 더 먹기도 합니다.


타입스크립트 incremental과 린트를 빌드 잡에서 분리하면 피크가 낮아집니다. 타입체크 잡을 따로 두고 빌드 잡의 메모리를 빌드에만 쓰는 식입니다. 한국에서 혼자 돌리는 소형 사이트는 이 분리만으로 무료 러너에 남는 경우가 있습니다.


빌드와 타입체크를 나누기
# CI 잡 1 npx tsc --noEmit # CI 잡 2 NODE_OPTIONS=--max-old-space-size=4096 npx next build
  • [ ] 로그에 heap out of memory가 있는지 확인했다
  • [ ] 종료 코드가 137인지 1인지 구분했다
  • [ ] 러너/컨테이너 RAM과 힙 상한을 비교했다
  • [ ] public 원본 이미지 용량을 줄였다
  • [ ] NODE_OPTIONS를 공식 플래그만으로 넣었다

빌드 중 이미지와 번들이 메모리를 차지하는 개념 이미지
큰 원본 이미지를 빌드가 한꺼번에 열면 힙이 먼저 찬다

로컬은 되고 CI만 죽을 때

노트북 RAM이 러너보다 큽니다. 맥 16GB에서 되던 빌드가 7GB 러너에서 137이 납니다. 로컬에서 NODE_OPTIONS=--max-old-space-size=2048로 한도를 낮춰 재현하면 CI와 비슷해집니다.


스왑을 CI에 넣는 방법은 느리고, 호스티드 러너에선 막혀 있을 수 있습니다. 의존하지 마세요. 셀프 호스티드라면 스왑은 최후입니다.


버셀 빌드는 플랫폼 한도가 따로 있습니다. 로컬 next build와 클라우드 빌드 머신 사양이 다릅니다. 타임아웃은 다른 글이고, 여기서는 메모리 부족만 봅니다.


확인되지 않은 플래그 금지 | 블로그에 떠도는 --optimize-for-size 조합을 그대로 붙이지 마세요. Node.js CLI 문서에 있는 --max-old-space-size와 NODE_OPTIONS만 씁니다.


문법 에러 로그와 섞지 않기

힙 부족은 스택 한 줄이 아니라 FATAL ERROR 블록입니다. ESLint 실패나 타입 에러는 종료 코드 1에 파일 경로가 있습니다. 둘을 한 커밋에서 고치려다 플래그만 올리면 타입 에러가 남습니다.


모듈을 못 찾아 빌드가 일찍 끝나면 메모리를 쓰기 전입니다. 그 줄은 Cannot find module입니다. npm 스크립트가 1로 끝나면 ELIFECYCLE이 따라붙습니다. 137은 그 위 단계입니다.


제가 돌리는 사이트 빌드도 이미지 폴더가 커진 주에 통합 환경만 죽었습니다. 원본을 줄인 뒤 힙 숫자는 4096에 멈췄습니다. 더 올리지 않은 이유는 러너 천장 때문이었습니다. 혼자 운영하면 노트북이 넉넉해 원인을 늦게 알아챕니다. 배포 쪽 기계를 기준으로 한 번 재현해 보는 버릇을 들이는 편이 낫습니다.


로그종료다음
heap out of memory종종 137힙·러너·이미지
Type error / ESLint1해당 파일
ELIFECYCLE스크립트 실패 래퍼그 위 실제 원인

로컬 노트북과 CI 러너의 메모리 용량이 다른 개념 이미지
로컬 16GB에서 된 빌드가 작은 러너에서는 SIGKILL로 끝난다

참고 자료


내부 연계: CI만 스크립트 실패, 모듈을 찾을 수 없음, ERESOLVE, 액션 동시성, 노드 테스트


인용한 동작은 2026년 8월 공개 문서 기준입니다.


자주 묻는 질문

종료 코드 137이면 무조건 힙을 올리면 되나요?

아닙니다. 137은 SIGKILL입니다. 러너 RAM보다 큰 힙을 주면 더 빨리 죽습니다. 힙 메시지와 컨테이너 한도를 같이 보세요.


--max-old-space-size 단위는 GB인가요?

메가바이트 정수입니다. 4096이 약 4GB입니다. 4처럼 작은 수를 넣으면 금방 다시 죽습니다. Node.js CLI 문서를 따르세요.


package.json 스크립트에 넣어도 넥스트가 무시합니다.

NODE_OPTIONS는 노드 프로세스가 읽습니다. 셸이 변수를 지웠거나, 다른 패키지 매니저가 환경을 덮으면 빠집니다. CI 잡 env에 명시하세요.


스왑을 켜면 해결되나요?

느려질 뿐 근본이 아닙니다. 호스티드 러너에선 못 켤 수도 있습니다. 이미지 축소와 잡 분리가 먼저입니다.


로컬에서 재현이 안 됩니다.

힙 상한을 러너보다 작게 걸어 보세요. 그래도 안 나면 CI만 큰 소스맵이나 캐시 없는 콜드 빌드일 수 있습니다.


버셀 빌드만 죽습니다.

플랫폼 빌드 머신 RAM이 노트북과 다릅니다. 로컬 성공은 증거가 아닙니다. 빌드 로그의 FATAL ERROR와 이미지 용량부터 보세요.


137은 메모리가 모자란 쪽에서 프로세스를 죽인 숫자입니다. 힙 메시지와 러너 RAM을 맞추고, 이미지를 줄인 뒤에야 공식 --max-old-space-size를 올리세요. 관련 글: CI 스크립트 실패, 모듈 없음, 액션 동시성.


Heap out of memory137max-old-space-sizeNODE_OPTIONSNext.jsNode.jsCI도커깃허브 액션개발자빌드V8

함께 보면 좋은 문제 해결

EXPLORE / Programming Languages

이어서 읽어보기

전체 토픽 둘러보기