- Published on
성능·Core Web Vitals 2025 완전 정복: LCP·CLS·INP, Real User Monitoring vs Synthetic, Critical Rendering Path, JS 번들·Image·Font 최적화, Caching·Edge·CDN·HTTP/3, Vercel Speed Insights·CrUX·PageSpeed, 한국 네트워크 특성 — Season 6 Ep 6
- Authors

- Name
- Youngju Kim
- @fjvbn20031
프롤로그 · 성능은 기능이 아니다
개발자들이 자주 착각하는 것: "성능 최적화는 기능 출시 후의 튜닝". 2025년 현실은 다르다.
- Google 검색 순위에 Core Web Vitals 반영 (2021~)
- 이커머스에서 LCP 0.1초 개선당 전환율 1%+ 연구 (Amazon, Booking)
- 2024년 INP 정식 적용 후 반응성 최적화 경쟁
- 한국 사용자의 지하철 5G·저전력 모드 현실
"성능은 기능이 아니다. 모든 기능의 조건이다."
좋은 AI·좋은 UX·좋은 모션도 느리면 아무 가치 없다. 이번 글은 2025년 실전 성능 가이드.
1장 · Core Web Vitals 2025 — 3대 지표
LCP (Largest Contentful Paint)
- 가장 큰 콘텐츠가 뷰포트에 렌더된 시점
- Good: ≤ 2.5초, Needs Improvement: ≤ 4초, Poor: > 4초
- 보통 Hero 이미지·텍스트 블록
CLS (Cumulative Layout Shift)
- 뷰포트 이동(레이아웃 시프트) 누적
- Good: ≤ 0.1, Needs: ≤ 0.25, Poor: > 0.25
- 이미지 size 미지정·광고 삽입·폰트 로드 등이 주범
INP (Interaction to Next Paint) — 2024 FID 대체
- 사용자 상호작용 → 다음 페인트까지 걸린 시간
- Good: ≤ 200ms, Needs: ≤ 500ms, Poor: > 500ms
- 느린 JS·메인스레드 블록 탐지
- FID(First Input Delay)보다 페이지 생애 전체 평가
측정 기준
- p75 (75 백분위수) — 대부분 사용자 경험
- Real users, 28일 rolling (CrUX)
- Mobile·Desktop 분리 평가
보조 지표
- FCP (First Contentful Paint): 1.8초 목표
- TTFB (Time to First Byte): 0.8초 목표
- TTI (Time to Interactive): 오래된 지표, INP가 대체
2장 · RUM vs Synthetic — 무엇을 측정할까
Synthetic (합성 테스트)
- 도구가 제어된 환경에서 시뮬레이션
- Lighthouse, WebPageTest, SpeedCurve
- 장점: 재현성, 회귀 감지
- 단점: 실사용자와 괴리
RUM (Real User Monitoring)
- 실제 사용자 브라우저에서 측정
- Vercel Speed Insights, Datadog RUM, New Relic Browser, Sentry, CrUX
- 장점: 진짜 경험 반영
- 단점: 노이즈, 소수 사용자 영향 큼
병행 원칙
- CI에서 Lighthouse (회귀 감지)
- Production에서 RUM (진짜 성능)
- CrUX 월간 리뷰로 경쟁사 벤치마크
CrUX (Chrome User Experience Report)
- Google이 Chrome 사용자 데이터 수집 (opt-in)
- 익명 집계, 월 단위 업데이트
- PageSpeed Insights가 이를 활용
- BigQuery 공개 데이터셋
3장 · Critical Rendering Path
브라우저의 렌더 파이프라인
- Network: HTML 다운로드
- Parse HTML → DOM
- Parse CSS → CSSOM
- DOM + CSSOM → Render Tree
- Layout (크기·위치)
- Paint (픽셀)
- Composite (레이어 합성)
주요 병목
- Render-Blocking CSS: 외부 CSS 로드 중 렌더 불가
- Render-Blocking JS:
<script>파싱 중 DOM 파싱 중단 - Font Swap Period: 폰트 로드 전 FOIT/FOUT
2025년 표준 개선 기법
(1) Critical CSS Inline
- Above-the-fold CSS를
<style>로 인라인 - Next.js·Astro·Vite 플러그인 자동화
(2) defer / async JS
<script defer>: 문서 끝까지 실행 지연<script async>: 독립 실행
(3) fetchpriority
<img fetchpriority="high">로 우선순위- LCP 이미지에 필수
(4) preconnect / dns-prefetch
- 외부 도메인 핸드셰이크 미리
<link rel="preconnect" href="https://cdn.example.com">
(5) preload
- 중요 리소스 미리 로드
- 폰트·Hero 이미지 등
4장 · JS 번들 다이어트
2025년 번들의 "좋은 크기":
- Initial: < 170kb gzipped
- Per route: < 50kb
- 모바일 환경에서 Parse·Execute 비용 고려
번들러 지형 2025
- esbuild: 가장 빠른 Go 기반
- swc: Rust 기반, Next.js 내부
- Rollup: 라이브러리·트리셰이킹
- Turbopack: Next.js 15 기본, Rust 기반 Webpack 후계
- Vite: 개발 서버 최고, 번들은 Rollup
- Rspack: Rust 기반 Webpack 호환
- Bun: 런타임+번들러 통합
번들 분석 도구
- Bundle Analyzer (Next.js, Vite)
- source-map-explorer
- Rollup visualizer
- Bundlephobia: 패키지 크기 사전 조회
흔한 문제
(1) 무거운 라이브러리
moment→date-fnsordayjslodash전체 → 개별 importreact-icons→ svg 직접
(2) 사용 안 하는 코드
- 트리셰이킹 안 되는 CJS 패키지
"sideEffects": false명시
(3) Dynamic Import
- 차트·모달 등 지연 로드
const Chart = dynamic(() => import('./Chart'))
(4) Polyfill 과잉
- 타겟 브라우저 명확히 (Baseline 2024)
- core-js 선택적 import
(5) CSS-in-JS 오버헤드
- 런타임 CSS-in-JS → zero-runtime (linaria, Vanilla Extract, Pigment)
- Tailwind·CSS Modules 대세
5장 · Image 최적화 — LCP의 핵심
포맷 선택 (2025)
| 포맷 | 용도 | 압축률 | 지원 |
|---|---|---|---|
| AVIF | 최신 | 최강 (~50% vs JPEG) | 모던 브라우저 |
| WebP | 표준 | JPEG 대비 30% | 모든 모던 |
| JPEG | 사진 | 기본 | 100% |
| PNG | 투명·단순 | 무손실 | 100% |
| SVG | 벡터 | 작음 | 100% |
2025년 권장: AVIF + WebP + JPEG 폴백
반응형 이미지
<img srcset="..." sizes="...">로 기기별 최적 이미지- 또는
<picture>로 포맷별 분기
Next.js Image 컴포넌트
import Image from 'next/image';
<Image
src="/hero.jpg"
width={1200}
height={600}
priority // LCP 후보
alt="Hero"
placeholder="blur"
blurDataURL={blur}
/>
- 자동 AVIF/WebP 변환
- 반응형 srcset 생성
- Lazy load 기본 (priority만 eager)
- CLS 방지 (width·height 필수)
Astro Image / Astro Assets
- 빌드 타임 최적화
getImage()API로 고급 제어
CDN 이미지 서비스
- Cloudinary, Imgix, Bunny, Cloudflare Images
- 실시간 변환·캐싱
주요 팁
- 항상 width·height 지정 (CLS 0)
- Lazy Load + priority 혼합
- LCP 이미지는 preload + fetchpriority=high
- Hero 이미지는 인라인 SVG·data-URL 검토
6장 · Font 최적화
핵심 이슈
- 폰트 로드 지연 → 텍스트 보이지 않음(FOIT) 또는 전환 깜빡(FOUT)
- CLS 발생
font-display 설정
@font-face {
font-family: 'Pretendard';
src: url('/fonts/pretendard.woff2') format('woff2');
font-display: swap; /* 기본 폰트 먼저, 로드 후 교체 */
}
swap: 기본 폰트 먼저 (CLS↑), 가장 빠름optional: 100ms 안에 로드 안 되면 기본 폰트 유지 (CLS↓)fallback: swap과 optional 중간
size-adjust·ascent-override
- 기본 폰트와 웹폰트 메트릭 맞춤
- CLS 대폭 감소
@font-face {
font-family: 'Pretendard-fallback';
src: local('Arial');
size-adjust: 105%;
ascent-override: 90%;
}
서브셋팅
- 한국어 폰트는 크기가 큼 (2-3MB) → 자주 쓰는 글자만
- 주요 자주 사용 문자 (KS X 1001 기본)
- Subfont 도구로 자동 서브셋
Variable Font
- 하나의 파일로 여러 굵기·너비·스타일
font-variation-settings- Pretendard Variable 공개 (국산 대표)
2025년 권장 스택
- Pretendard Variable (한글)
- Inter / Geist (영문)
- Noto Sans KR (폴백)
font-display: swap+size-adjust
7장 · Caching 전략
HTTP 캐시
- Cache-Control: 가장 중요한 헤더
public, max-age=31536000, immutable— 정적 리소스no-cache— 항상 검증no-store— 절대 저장 X
- ETag / Last-Modified — 조건부 요청
- Stale-While-Revalidate — 만료 후에도 써도 되나 백그라운드 갱신
Next.js 15 Caching (재설계)
- Request Memoization: 동일 요청 중복 제거
- Data Cache: 서버 fetch 응답 캐시
- Full Route Cache: 정적 페이지 HTML
- Router Cache: 클라이언트 라우터 캐시
- 2025년부터
use cache지시어로 명시적 opt-in
Service Worker
- Offline, App-shell, Cache-first for assets
- Workbox로 구현 편의
- 2025년 PWA 부활 조짐 (iOS 제한 완화 움직임)
Edge Caching
- CDN 레벨 캐시 (Vercel, Cloudflare, Fastly)
stale-while-revalidate로 체감 속도↑- ISR (Incremental Static Regeneration) — Next.js 대표 기법
8장 · Edge·CDN·HTTP/3
CDN의 역할
- 지리적 가까운 서버에서 응답
- 원본 서버 부하 감소
- TLS·HTTP/3·압축 오프로딩
2025년 주요 CDN
- Cloudflare: 가격·기능 밸런스 최강
- Vercel Edge Network: Next.js 친화
- Fastly: 개발자 친화, VCL
- AWS CloudFront: AWS 생태계 통합
- Netlify Edge: JAMstack 친화
- 한국: Toast KRP, 네이버 클라우드 CDN, KT 올레CDN
Edge Function
- CDN 레벨에서 로직 실행
- Cloudflare Workers, Vercel Edge, Deno Deploy, Fastly Compute@Edge
- Cold Start 거의 없음 (V8 Isolate)
- 사용 사례: A/B, 인증, Rate Limit, i18n
HTTP/3 (QUIC)
- UDP 기반, Head-of-line Blocking 해결
- TLS 1.3 내장, 0-RTT 연결
- 2025년 CDN·주요 사이트 기본
- 모바일·불안정 네트워크에서 특히 이점
한국 네트워크 특성
- 지하철 5G: 혼잡·지연·패킷 로스
- 공공 WiFi: 제한·광고 프록시
- KT·SKT·LGU+ 통신사별 라우팅 차이
- → Edge·CDN이 특히 중요
9장 · INP 최적화 — 반응성 실전
INP의 원인
- 긴 작업(long task) >50ms 이 메인 스레드 점유
- 상호작용 처리 지연
실전 기법
(1) Debounce / Throttle
- 검색 input·스크롤 리스너
(2) Scheduler API (Chrome)
scheduler.postTask(() => heavyWork(), { priority: 'background' });
(3) useDeferredValue / useTransition (React 18+)
const [isPending, startTransition] = useTransition();
startTransition(() => setQuery(input));
(4) Web Workers
- 무거운 계산·정렬을 워커로
(5) Virtualization
- 긴 리스트에
react-window,TanStack Virtual
(6) Code Splitting
- 필요할 때만 로드
측정
- Chrome DevTools Performance "INP" 기록
- Long Task API로 production 감지
10장 · Vercel Speed Insights·CrUX·PageSpeed
Vercel Speed Insights
- Vercel 배포 프로젝트에 간단 통합
- RUM 데이터, Web Vitals 자동
- 페이지별·시간별 분해
- 가격: Pro 플랜 포함
Datadog RUM / New Relic Browser
- 엔터프라이즈 APM과 통합
- 사용자 세션 리플레이, 에러 추적
- 가격 비쌈
CrUX Dashboard
- Google이 제공 무료 도구
- site-level, origin-level 리포트
- CrUX API·BigQuery로 자동화
PageSpeed Insights
- Google 무료 도구
- Lighthouse + CrUX 결합
- SEO·Accessibility·Best Practices까지
WebPageTest
- 가장 정교한 Synthetic
- 다양한 위치·네트워크·디바이스
- 워터폴 차트, 필름 스트립
11장 · 실전 체크리스트 · 성능 린터
프로젝트 초기 설정
- Next.js/Astro Image 활용
- font-display: swap + size-adjust
- Critical CSS (프레임워크 기본)
- Bundle Analyzer 설치
- Lighthouse CI 설정 (threshold:
LCP<2.5s,CLS<0.1,INP<200ms) - Vercel Speed Insights 또는 자체 RUM
릴리즈 전 체크
- LCP 원인 분석 (DevTools "Performance insights")
- INP 이벤트 핸들러 점검
- CLS 이미지 size 확인
- 번들 < 170kb
- 핵심 폰트 preload
- 3G Fast 에뮬레이션 테스트
릴리즈 후 모니터링
- RUM 75p 추이
- 사고 시 롤백·수정
- 주간 Performance Review 팀 미팅
12장 · 2025년 고급 패턴
Partial Pre-Rendering (PPR)
- Next.js 15: 정적 셸 + 동적 홀
- LCP 극단 단축 + 개인화 공존
Islands Architecture
- Astro: 기본 정적 + JS 섬만 하이드레이트
- 번들 최소화
Qwik Resumability
- 초기 JS 0에 가까움
- 상호작용 필요 시점에 로드
Bun/Deno 런타임
- Node.js 대비 시작·런타임 속도
- 일부 프로덕션 도입 시작
Turbopack
- Next.js 15 기본
- Dev 서버·빌드 속도 혁명
Server-sent Streaming
- RSC·Suspense로 콘텐츠 조각 전송
- TTFB·LCP 개선
13장 · 다음 글 예고 — Season 6 Ep 7: "접근성과 국제화"
성능을 잘 만들어 놓았다면 다음은 모두가 쓸 수 있는 제품. Ep 7은 접근성(a11y)과 국제화(i18n).
- WCAG 2.2 실전 체크리스트
- Screen Reader 테스트 (NVDA·VoiceOver)
- 키보드 내비게이션 설계
- ARIA 패턴과 오남용
- 색 대비·모션·폰트 크기
- EU Accessibility Act 2025·ADA·한국 장애인차별금지법
- i18n: next-intl·react-intl·vue-i18n·Format.js
- Locale-aware 숫자·날짜·통화
- 한국어 타이포그래피의 특수성 (조사·줄바꿈·세로 쓰기)
- 일본·중국어·RTL(아랍어·히브리어) 지원
- AI·LLM의 다국어 품질
"접근성은 소수의 권리가 아니다. 모두의 품질이다."
다음 글에서 만나자.
에필로그 · 체크리스트 12
- Core Web Vitals p75 기준을 RUM으로 추적하는가?
- LCP < 2.5s, CLS < 0.1, INP < 200ms 를 달성하는가?
- LCP 이미지에 priority + fetchpriority=high 설정되는가?
- 모든 이미지에 width·height 가 지정되는가?
- 폰트가 font-display + size-adjust 로 FOIT/CLS 방지되는가?
- 번들이 초기
<170kb, 라우트<50kb인가? - Dynamic Import·Code Splitting 을 적극 활용하는가?
- CDN·Edge Caching 이 설정되어 있는가?
- HTTP/3 가 활성화되어 있는가?
- Lighthouse CI로 회귀 감지되는가?
- Vercel Speed Insights 또는 RUM 운영되는가?
- 한국 네트워크·모바일 실사용자 경험이 고려되는가?
"빠른 제품은 좋은 제품이다. 느린 제품은 존재하지 않는 제품이다."
— Season 6 Ep 6, Fin.