Turbopack HMR 지연, 실제로 벤치마크 수치만큼 빠른가?
조건에 따라 다르다. 공식 벤치마크가 제시하는 수치(15ms급)는 특정 생성 애플리케이션과 특정 측정 프로토콜에서 나온 값이고, 실제 프로젝트에서는 변경 파일이 의존성 그래프의 어디에 위치하느냐가 체감 지연을 좌우한다. 2026년 기준으로 Turbopack을 도입한 팀 다수가 "콜드 스타트는 분명히 빨라졌는데 HMR이 가끔 느리다"는 보고를 반복한다.
핵심 정리(미리 보기)
- Turbopack 공식 벤치마크의 15ms는 워밍업 5회 후 6번째 변경을 10회 측정한 특정 조건의 평균값이다 출처.
- HMR 지연은 "프로젝트 전체 모듈 수"가 아니라 변경이 전파되는 dirty 계산 셀의 범위에 비례한다.
- Next.js 16.3은 청크 추적 구독을 단일화해 콜드 스타트를 15% 이상 단축했다고 발표했지만, 이는 HMR 자체의 절대값을 보장하지 않는다 출처.
- 파일시스템 캐시는 "재시작 후 복원"을 위한 것이지 실행 중 HMR 속도 자체를 바꾸는 장치가 아니다.
- 벤치마크 재현성을 보장하려면 하드웨어, 캐시 상태, 측정 시작/종료점을 함께 기록해야 한다.
시간순으로 보면 증상은 이렇게 드러났다. 마이그레이션 직후에는 개발 서버 콜드 스타트가 체감상 빨라졌다는 보고가 들어왔다. 며칠 뒤부터 특정 공용 모듈을 수정했을 때만 HMR이 수백 ms까지 늘어난다는 보고가 섞여 들어오기 시작했다. 동일한 프로젝트에서 리프 모듈을 고치면 체감상 즉시 반영되는데, 특정 파일을 고치면 눈에 띄게 멈칫거리는 패턴이 반복됐다. 공식 벤치마크 수치(15ms)와 비교하면 수십 배 차이였고, 팀 내부에서는 "툴 자체의 문제인가, 우리 코드 구조의 문제인가"를 두고 가설이 갈렸다.
Rust 기반이니 HMR이 항상 밀리초 단위여야 하는 거 아닌가?
기각된 가설이다. 공개된 Turbopack HMR 벤치마크의 15ms는 생성된(synthetic) 애플리케이션에서 개발 서버를 띄운 뒤 5회 워밍업, 6번째 파일 변경을 10회 측정한 평균이며, 측정 구간은 "파일 변경부터 브라우저에서 변경 코드가 실행된 시점까지"로 정의돼 있다 출처. 이 조건은 실제 프로덕션 코드베이스의 파일 구조, 모듈 간 참조 밀도, 사용 중인 브라우저 환경과 다르다. 같은 벤치마크 문서조차 전체 하드웨어·OS·정확한 패키지 버전을 충분히 공개하지 않았다는 점에서, 이 수치를 "Rust 런타임이면 항상 재현되는 물리적 하한선"으로 해석하는 것 자체가 과도한 일반화다. Rust로 작성됐다는 사실은 언어 수준의 오버헤드를 줄여줄 뿐, 의존성 그래프가 넓게 퍼진 변경까지 똑같이 몇 ms에 처리해 준다는 보장은 아니다. 이 가설은 "툴이 느리다"는 결론으로 이어지기 쉽지만, 실제로는 측정 조건의 불일치를 "툴의 성능 저하"로 오독한 것에 가까웠다.
모듈 수가 적어서 Turbopack 이점이 안 나온 걸까?
이것도 지연의 직접 원인은 아니었다. 같은 벤치마크 자료는 애플리케이션이 3만 모듈 이상일 때 Turbopack HMR이 Vite보다 약 10배, 5만 모듈 이상에서는 약 20배 빠르다고 설명한다. 다만 이 배수의 원자료 표와 하드웨어 조건이 검색 결과에 함께 노출되지 않아, 이는 "공식 벤치마크의 주장"으로만 인용하는 게 안전하다 출처. 대상 프로젝트는 수만 모듈 규모였고, 그 기준으로 보면 "모듈 수가 적어서 이점이 안 나온다"는 가설은 성립하지 않는다. 오히려 모듈 수가 충분히 많았는데도 특정 변경에서만 지연이 발생한다는 점이, 이 가설을 기각하는 결정적 신호였다. 제3자 비교 자료에서도 10,000모듈 규모에서 Turbopack HMR을 약 50ms로 제시하지만, 부하 구성과 변경 파일 위치가 검증되지 않아 보조 사례로만 참고했다 출처. 결국 "모듈 총량"은 범인이 아니었다.
파일시스템 캐시가 깨져서 느려진 걸까?
이 가설도 메커니즘 자체를 오해한 결과였다. Turbopack의 next dev 파일시스템 캐시는 의존성 그래프, 집계 그래프, 중간 계산 결과를 디스크에 저장해 개발 서버 재시작 후 웜 캐시를 복원하는 장치다 출처. 즉 이 캐시는 "서버를 껐다 켰을 때" 콜드 스타트를 줄이기 위한 것이지, 서버가 떠 있는 동안 파일을 저장할 때마다 발생하는 HMR 반응 속도와는 별개 경로다. 캐시를 지우고 다시 켜 봐도 재시작 직후 1회차 빌드만 느려질 뿐, 문제가 된 "특정 파일 수정 시의 반복적 지연"은 재현됐다. 이는 증상의 트리거가 캐시 상태가 아니라 런타임 중 증분 계산 경로에 있다는 것을 보여줬다. 참고로 next build의 영속 캐시는 아직 실험적 기능으로 다뤄지며, 이는 개발 서버의 HMR 경로와는 또 다른 레이어라는 점도 가설 기각에 참고했다 출처.
그럼 실제 지연의 원인은 무엇이었나?
원인은 변경 전파 범위였다. Turbopack은 파일이 변경되면 그 파일을 읽은 계산 셀을 dirty 상태로 만들고, 영향을 받은 계산만 다시 실행하는 구조로 동작한다. 지연이 발생한 파일은 다수의 다른 모듈이 참조하는 공용 모듈이었고, 이 파일을 고치면 dirty 처리되는 계산 셀의 수가 리프 모듈을 고칠 때보다 훨씬 많았다. 즉 HMR 지연을 좌우하는 변수는 "프로젝트 전체 크기"가 아니라 "이번 변경이 의존성 그래프 상에서 얼마나 넓게 퍼지는가"였다. 공식 아키텍처 설명도 이 해석을 뒷받침한다 출처. 제3자 벤치마크에서도 루트에 가까운 변경과 리프 변경의 HMR 값이 7ms와 11ms로 서로 다르게 보고된 사례가 있는데, 수치 자체의 재현성은 별도로 검증해야 하지만 "변경 위치에 따라 값이 갈린다"는 방향성만큼은 이번 원인 분석과 일치했다 출처.
재발 방지를 위해 무엇을 바꿨나?
측정 프로토콜과 코드 구조 두 가지를 바꿨다. 첫째, HMR 지연을 보고할 때 변경 파일의 의존성 그래프상 위치(루트 근접/리프), 콜드·웜 상태, 측정 시작점(파일 저장)과 종료점(브라우저 반영)을 함께 기록하도록 체크리스트를 만들었다. 둘째, 다수 모듈이 참조하는 배럴(barrel) 성격의 공용 파일을 줄이고, 자주 수정되는 로직을 더 좁은 의존성 범위를 가진 모듈로 분리했다. 이는 변경 전파 범위 자체를 줄이는 구조적 대응이다. 셋째, CI와 로컬 모두에서 캐시 디렉터리 보존 여부를 명시적으로 로그에 남겨, "느려졌다"는 보고가 실제로는 캐시가 없는 빈 컨테이너에서 측정된 것인지부터 먼저 걸러내도록 했다.
다른 빌드 툴에도 적용되는 교훈은 무엇인가?
일반화하면 "증분 빌드 시스템의 체감 속도는 전체 규모가 아니라 변경 단위의 전파 범위로 평가해야 한다"는 것이다. 이는 Turbopack뿐 아니라 esbuild, Vite, Turborepo, Bazel류 캐시 기반 빌드 시스템에도 동일하게 적용된다. 공식 수치(예: Vercel이 보고한 4코어 2배, 14코어 2.2배, 30코어 기준 모듈 규모별 2.5~5배 출처)는 특정 하드웨어와 특정 프로젝트의 제품 성능 사례이지, 모든 환경에서 재현되는 물리 법칙이 아니다. 어떤 증분 빌드 도구를 평가하든 CPU·메모리·OS·버전·캐시 상태·측정 구간·반복 횟수를 함께 기록하지 않은 벤치마크는 판단 근거로 쓰지 않는 편이 안전하다.
핵심 정리
- Turbopack 공식 HMR 벤치마크(15ms)는 생성 애플리케이션, 5회 워밍업, 10회 측정이라는 특정 조건의 평균값이며 모든 프로젝트에 고정 적용되지 않는다.
- HMR 지연은 모듈 총량이 아니라 변경이 전파되는 dirty 계산 셀의 범위(공용 모듈 vs 리프 모듈)에 좌우된다.
- 파일시스템 캐시는 재시작 후 콜드 스타트 복원용이며, 실행 중 HMR 반응 속도와는 별개 메커니즘이다.
- Vercel이 보고한 2~5배 빌드 속도 향상은 특정 하드웨어·프로젝트의 제품 성능 사례로 인용해야 하며 일반 법칙으로 단정할 수 없다.
- 재현 가능한 비교를 위해서는 하드웨어, 버전, 캐시 상태, 측정 시작/종료점, 변경 파일 위치를 반드시 함께 기록해야 한다.
자주 묻는 질문
Turbopack HMR이 느려 보이면 가장 먼저 무엇을 확인해야 하나?
수정한 파일이 몇 개의 다른 모듈에서 참조되는 공용 모듈인지부터 확인한다. 참조가 많은 배럴 파일이나 루트에 가까운 설정 파일을 고쳤다면 지연이 커지는 것은 캐시 문제가 아니라 변경 전파 범위 때문일 가능성이 높다.
공식 벤치마크 수치를 사내 성능 목표로 써도 되나?
권장하지 않는다. 15ms, 2~5배 같은 수치는 특정 하드웨어·프로젝트·측정 프로토콜에서 나온 값이므로, 사내 목표로는 자체 프로젝트에서 측정한 콜드/웜 HMR 값과 p95를 기준으로 삼는 것이 안전하다.
Webpack에서 Turbopack으로 전환하면 HMR이 항상 빨라지나?
일반화된 보장은 아니다. 공식 자료가 확인해 주는 것은 특정 조건에서의 증분 계산 구조와 캐시 메커니즘, 그리고 Vercel이 측정한 일부 프로젝트의 수치일 뿐이며, 의존성 그래프가 복잡하거나 공용 모듈이 많은 프로젝트에서는 체감 개선 폭이 벤치마크보다 작을 수 있다.
next build의 영속 캐시를 CI에 적용할 때 주의할 점은?
해당 기능은 실험적이며, 캐시 디렉터리를 CI에서 실제로 복원하지 않으면 웜 캐시 이득이 사라진다. 콜드 빌드와 후속 빌드를 분리해 측정하고, 매번 빈 컨테이너에서 실행되는지 여부를 로그로 남겨야 효과를 제대로 판단할 수 있다.
더 알아보기
빌드·번들 툴체인 완전 가이드: 증분성·캐시·병렬성의 측정 — 이 주제의 종합 가이드