Next.js 13 -> 14 마이그레이션

정태수·2025년 5월 24일
post-thumbnail

프로젝트에서 Next.js 13을 사용하던 중, 특정 API 요청에 대해 초기 응답 시간이 10~15초가량 지연되는 현상이 발생했다.
단순한 API 응답 지연이 아닌, 첫 요청 시에만 발생하는 일회성 지연이라는 점에서 콜드 스타트(cold start)를 의심하게 되었고, 본격적인 문제 분석과 해결에 착수했다.

모든 요청이 정상적인 200이나 304 상태 코드였지만, 첫 로딩 시만 비정상적으로 긴 대기 시간

뭐냐,, 왜 12초나 걸리는거냐. 너..

이후 동일 요청은 매우 빠르게 처리됨

이 현상은 Vercel 또는 서버리스 환경에서 발생하는 대표적인 cold start 패턴이었다.

Cold Start란?

콜드 스타트는 서버리스 환경에서 자주 발생하는 문제로,
초기 요청 시 런타임 환경을 새로 띄우는 시간 지연 현상을 말한다.

특히 Next.js의 기반 프로젝트에서는 dynamic import 또는 lazy loading

ESM 패키지 처리 방식이 복합적으로 작용해 cold start latency가 증가할 수 있다.

  1. Next.js는 node_modules의 external dependencies를 번들에 포함하지 않고 런타임에 require()또는 dynamic때 읽는다.
    이 경우, vercel 서버리스 함수는 실행시 해당 모듈을 찾기 위해 디스크 I/O를 수행
    파일 탐색 + 모듈 해석에 시간이 든다.
  2. 일정 시간동안 요청이 없으면 인스턴스는 종료되서 만약 콜드 스타트가 되어서 런타임때에 transpile 미리 안해놓으면 ESM 패키지들을 처리하기에 더 느려진다. (ESM 패키지를 transpilePackages로 사전 처리하면 런타임 로딩 부담 감소)

✅ ESM 패키지 transpile 및 cheerio import 방식 수정 등 구조적 안정성 확보
✅ NumericFormat 타입 오류 해결을 포함한 TypeScript 문제 처리


// next.config.js
module.exports = {
  transpilePackages: ['cheerio', 'rc-util', 'lodash-es'],
}

업데이트 후 Vercel 로그 비교

왼쪽이 Next.js@13 , 우측 사진이 Next.js@14 이다. Vercel에서 로그표시도 달라졌다.

Next.js 13에서 getStaticProps + revalidate 사용 시,

사용자가 해당 페이지에 요청을 보냈을 때, 만약 캐시 만료되었다면:
새로 데이터를 fetch하고 HTML을 재생성한 뒤 응답
이때 문제는, ISR이 실제 유저 요청과 동기적으로 묶여 있음

→ 결과적으로 콜드 스타트 + API fetch 지연 + HTML 생성이 겹치면
→ 한 요청에 10초, 15초 이상 걸리는 경우가 생긴다.

Next.js 14에서는 ISR 구조를 바꿔서:

유저가 요청을 보내면 → 기존 캐시된 HTML을 즉시 반환

동시에 백그라운드에서 API fetch + 캐시 갱신 작업을 실행

이 재생성된 HTML은 다음 요청에 쓰임

즉, ISR Cache updated는 사용자 응답 이후에 이뤄지는 구조.

Vercel 로그에 Background Revalidation으로 찍힘
Execution Duration: 136ms 처럼 엄청 빠르게 응답한 것도, 캐시가 먼저 반환되서.

profile
프론트엔드 개발자

0개의 댓글