이미지 초기 렌더링 99.05% 개선 (8.21s → 78ms)
커넥트립 인트로 페이지의 첫 이미지가 prod에서 최대 8.21초까지 늦게 떴다. "브라우저 캐시겠지"로 시작한 추적이 서버 SSH까지 들어갔고, 최종적으로 78ms까지 내려왔다.
배경: 인트로 페이지 도입
로그인 필수 서비스라 첫 화면에 카카오 로그인 버튼만 있고 서비스 소개가 없었다. 유입을 위해 Next/Image로 여러 PNG 이미지를 버튼으로 넘기는 인트로 페이지를 추가했다.
문제: 첫 이미지가 4~5초, 최대 8.21초
prod 배포 후 첫 이미지를 불러올 때 평균 4~5초(최대 10초 이상)가 걸렸다. 한 번 캐싱되면 새로고침 시 밀리초로 빨라졌다. (영상 기준 한 번 로딩에 8.21초.)
이상했던 건, 다른 페이지의 Next/Image(PNG→WebP 변환)는 빠른데 여기만 느렸다는 점, 그리고 Lighthouse 점수는 오히려 높게 나왔다는 점이었다.

시도 — 그리고 실패
- Next/Image
priority·eager— 로딩 우선순위 설정. 유의미한 개선 없음. - PNG → SVG 대체 — 빨라졌지만 파일이 1.2MB까지 커져 용량 문제로 부적절.
- 일반
<img>태그 — 초기 로딩은 다소 개선됐지만 여전히 2초+, 재로딩 성능·용량 모두 나빠짐.
세 시도 모두 근본 원인이 아니었다.
원인 발견: 브라우저가 아니라 서버 캐싱
브라우저 캐시를 지워도 재현되지 않았다. 그래서 dev 서버에 직접 SSH로 접속해 서버 캐시를 지워봤다.
ssh -i ~/key/deploy.pem ubuntu@<dev-server>
docker ps # 블루/그린 컨테이너 확인
docker exec -it front-blue /bin/sh
cd /app/.next/cache/images && rm -r ./* # 이미지 캐시 삭제.next/cache/images를 지우고 다시 접속하니 그 n초 로딩이 그대로 재현됐다. 즉 범인은
Next/Image의 서버 측 최적화·캐싱 시간이었다. 캐싱 전후는 응답 헤더로도 확인됐다.
- 캐싱 전:
X-Nextjs-Cache: MISS - 캐싱 후:
X-Nextjs-Cache: HIT

.next/cache/images에 최적화 캐시가 생성된다.
X-Nextjs-Cache: MISS
X-Nextjs-Cache: HIT1차 해결 시도: 배포 시 캐시 프리워밍
"유저가 처음 요청할 때만 느리다면, 배포 스크립트에서 최적화 이미지 링크를 미리 1회 요청해
캐싱해두면 되지 않을까?" 캐싱된 images 폴더를 지운 뒤 curl로 이미지를 미리 요청하면 캐시가
채워졌다.

curl로 이미지를 미리 요청(프리워밍).그런데 문제가 있었다. Next/Image는 유저 화면 크기마다 다른 URL을 생성한다.
/_next/image?url=%2Fintro%2F1.png&w=1200&q=75
/_next/image?url=%2Fintro%2F2.png&w=1200&q=75
...w= 값이 뷰포트마다 달라, 미리 데운 캐시가 모든 사용자에게 맞지 않았다.
최종 해결: 고정 크기 WebP + CDN
매 요청 최적화 비용·무거운 PNG·오리진 직접 전송을 한 번에 없앴다.
- Sharp로 이미지 최적화
- PNG → WebP 변환으로 용량 축소
- 첫 화면 이미지를 고정 크기 WebP로 미리 만들어 AWS S3 + CloudFront CDN에서 캐싱·전송
화면 크기마다 캐시가 갈리던 문제를 고정 크기로 없애고 CDN 엣지에서 전송하니, 초기 로딩이 99.05% 개선(8.21s → 78ms).

배운 점
- "브라우저 캐시겠지"로 넘기지 않고 서버에 직접 들어가 재현한 게 원인 규명의 핵심이었다.
- Next/Image의
X-Nextjs-CacheMISS/HIT와 화면 크기별 URL 생성을 이해하니, 프리워밍이 왜 안 통하는지까지 설명할 수 있었다. - 포맷(WebP)·CDN·고정 크기는 따로면 효과가 작고, 세 가지를 함께 맞춰야 큰 개선이 난다.