Next.js 16 성능 최적화 체크리스트: 번들·이미지·캐시·배포

2025.12.05·수정 2026.09.12·약 13분·작성: 해비·블로그 소개

학습 목표·선수 지식: 측정 환경을 고정하고 한 병목씩 검증합니다. 선수 지식: production build·Network 도구.

Next.js 성능 최적화 핵심 요약

Next.js 성능은 특정 배포 플랫폼을 고르는 것만으로 해결되지 않습니다. 먼저 실제 사용자의 Core Web Vitals를 측정하고, 클라이언트 JavaScript·이미지·폰트·데이터 캐시·배포 환경을 순서대로 점검해야 합니다. 이 글은 2026년 8월 Next.js 16 App Router 기준으로 오래된 설정을 바로잡고, 수정 전후를 검증하는 실무 체크리스트를 정리합니다.

먼저 바로잡을 오래된 기준

Next.js 성능 글은 버전 변화가 빨라 예전 예제를 그대로 적용하면 오히려 잘못된 설정이 들어갈 수 있습니다. 현재 글을 확인할 때는 다음 세 가지부터 구분해야 합니다.

  • App Router 메타데이터: App Router에서는 페이지별 SEO 설정에 next/head를 권장하지 않습니다. metadata 또는 generateMetadata를 사용합니다.
  • 이미지 우선 로딩: Next.js 16부터 Imagepriority 속성은 의미가 더 명확한 preload로 대체되었습니다. 첫 화면의 실제 LCP 이미지에만 제한적으로 적용합니다.
  • 캐시 설정: next.config 최상위에 next.revalidate 옵션을 두지 않습니다. fetch(url, { next: { revalidate: 300 } })의 옵션과 구분하세요. Cache Components를 켠 프로젝트는 use cache·cacheLife 등의 경계를 따로 정합니다.

버전이 다른 프로젝트에 최신 예제를 그대로 섞지 말고, 먼저 package.json의 Next.js 버전과 next.config의 Cache Components 사용 여부를 확인하는 것이 안전합니다.

1. Core Web Vitals를 먼저 측정합니다

성능 최적화는 Lighthouse 점수 하나를 높이는 작업이 아닙니다. 실제 사용자 환경의 LCP, INP, CLS를 기준으로 가장 큰 병목부터 줄여야 합니다. Search Console의 코어 웹 바이탈은 실제 사용자 데이터 흐름을 보는 데 유용하고, Lighthouse와 Chrome DevTools는 문제를 재현하고 원인을 좁히는 데 적합합니다.

  • LCP: 첫 화면의 핵심 이미지·제목·서버 응답이 늦는지 확인합니다.
  • INP: 큰 Client Component, 긴 JavaScript 작업, 무거운 이벤트 처리가 입력 반응을 막는지 확인합니다.
  • CLS: 이미지 크기, 광고·배너 자리, 늦게 로드되는 폰트 때문에 레이아웃이 이동하는지 확인합니다.

앱 안에서 실제 사용자 지표를 수집하려면 useReportWebVitals를 별도 Client Component에 두고 분석 도구로 전달할 수 있습니다.

"use client";

import { useReportWebVitals } from "next/web-vitals";

export function WebVitals() {
  useReportWebVitals((metric) => {
    console.log(metric.name, metric.value);
  });

  return null;
}

측정 코드는 필요한 페이지에만 추가하고, 운영 환경에서는 콘솔 출력 대신 사용하는 분석 서비스의 이벤트 전송 방식에 연결합니다.

Next.js 성능 점검: Core Web Vitals, JavaScript, 이미지·폰트

2. 클라이언트 JavaScript를 줄입니다

App Router에서는 Server Component가 기본입니다. 상태, 이벤트, 브라우저 API가 필요한 영역만 Client Component로 만들면 브라우저에 전달되는 JavaScript를 줄일 수 있습니다. 페이지 최상단에 무조건 'use client'를 붙이면 하위 모듈까지 클라이언트 번들에 포함될 수 있으므로 경계를 작게 잡아야 합니다.

첫 화면에 필요하지 않은 차트·에디터·지도처럼 무거운 Client Component는 동적 로딩을 검토합니다.

app/components/DashboardChart.tsx에 넣는 부분 통합 예제입니다. 같은 폴더의 AdminChart.tsx는 실제 차트 라이브러리를 사용하는 default export 컴포넌트로 별도 구현해야 합니다. 이 글은 차트 데이터·라이브러리와 AdminChart 파일을 제공하지 않습니다.

"use client";

import dynamic from "next/dynamic";

const AdminChart = dynamic(() => import("./AdminChart"), {
  loading: () => <p>차트를 불러오는 중입니다.</p>,
  ssr: false,
});

export function DashboardChart() {
  return <AdminChart />;
}

Server Component는 기본적으로 코드 분할되므로 모든 컴포넌트를 dynamic으로 감쌀 필요는 없습니다. 수정 전후에는 @next/bundle-analyzer로 큰 의존성과 중복 모듈을 확인하고, 단순히 파일 개수가 아니라 브라우저에 전달되는 JavaScript 크기가 실제로 줄었는지 비교합니다.

React 렌더 자체가 병목이라면 Next.js 렌더링 성능 최적화 기준에서 부모 렌더·props·메모이제이션 문제를 별도로 확인하는 편이 좋습니다.

3. 이미지와 폰트를 LCP 기준으로 최적화합니다

next/image를 사용해도 속성 선택이 잘못되면 LCP와 CLS가 나빠질 수 있습니다. 고정 크기 이미지는 widthheight를 제공하고, 반응형 fill 이미지는 실제 표시 폭에 맞는 sizes를 반드시 지정합니다.

app/components/Hero.tsx의 컴포넌트 예제입니다. public/hero.webp에 자신의 1200×630 이미지를 준비하고 페이지에서 Hero를 import해 렌더합니다. 이미지 파일은 이 개념 글에서 제공하지 않습니다.

import Image from "next/image";

export function Hero() {
  return (
    <Image
      src="/hero.webp"
      alt="서비스 핵심 화면"
      width={1200}
      height={630}
      sizes="(max-width: 768px) 100vw, 1200px"
      preload
    />
  );
}

preload는 화면 위에 있는 모든 이미지가 아니라, 해당 페이지의 실제 LCP 후보 한 개에 우선 적용합니다. 외부 이미지는 remotePatterns를 구체적으로 제한하고, 오류가 있다면 Next.js Image remotePatterns 점검을 함께 확인합니다.

폰트는 next/font로 로컬 호스팅과 서브셋을 관리하고, 사용하지 않는 굵기를 줄입니다. 이미지와 폰트 모두 최적화 기능을 켰다는 사실보다 실제 네트워크 전송량과 레이아웃 이동이 줄었는지 확인하는 것이 중요합니다.

4. 데이터 캐시와 스트리밍을 분리해서 설계합니다

캐시는 모든 데이터를 오래 저장하는 기능이 아니라, 변경 주기와 사용자별 범위가 맞는 데이터를 재사용하는 기능입니다. 공용 상품 목록과 사용자별 장바구니를 같은 기준으로 캐시하면 오래된 데이터나 개인정보 혼합 문제가 생길 수 있습니다.

Cache Components를 사용하지 않는 프로젝트에서는 다음처럼 재검증 시간을 명시할 수 있습니다.

const products = await fetch("https://api.example.com/products", {
  next: { revalidate: 300 },
}).then((response) => response.json());

데이터 변경 뒤 특정 화면을 갱신해야 한다면 Server Action이나 Route Handler에서 revalidatePath('/products')처럼 무효화 범위를 명시합니다. Cache Components를 활성화한 Next.js 16 프로젝트에서는 라우트·컴포넌트·함수 단위의 'use cache'와 캐시 수명 설정을 같은 프로젝트 규칙 안에서 사용합니다.

서버 응답 전체가 느리다면 캐시만 추가하지 말고 Suspense 경계를 이용해 먼저 보여줄 수 있는 UI와 늦게 도착하는 데이터를 나눕니다. 데이터 변경 후 화면이 그대로라면 Next.js fetch 캐시 문제 해결 순서에서 캐시 범위와 무효화 지점을 확인할 수 있습니다.

Next.js 성능 점검 해결: 데이터 캐시, 스트리밍, 배포 검증

5. 배포 환경은 지원 기능과 운영 책임으로 비교합니다

Next.js는 Vercel뿐 아니라 Node.js 서버, Docker 컨테이너, 정적 내보내기, 플랫폼 어댑터 방식으로 배포할 수 있습니다. 성능 차이는 플랫폼 이름보다 서버 위치, CDN, 이미지 최적화, 캐시 지속성, 콜드 스타트와 관측 도구 설정에서 발생합니다.

배포 방식확인할 장점직접 점검할 항목
VercelNext.js 기능 통합과 배포 설정이 단순함함수 리전, 캐시 정책, 이미지 사용량, 비용
Node.js·Docker인프라와 실행 환경을 직접 통제 가능리버스 프록시, CDN, 다중 인스턴스 캐시, 이미지 최적화
정적 내보내기정적 호스팅과 CDN 구성이 단순함서버 기능 제약, 동적 라우트·이미지 로더 대체 여부
플랫폼 어댑터기존 클라우드 환경과 연결 가능지원되는 Next.js 기능과 버전별 제한

플랫폼을 바꾸기 전에 같은 빌드에서 TTFB, LCP, 번들 크기와 서버 로그를 비교해야 합니다. 배포 자체가 실패하거나 라우팅이 깨진다면 프론트엔드 배포 오류 체크리스트로 문제를 먼저 분리합니다.

배포 전 성능 체크리스트

  • Lighthouse만 보지 않고 실제 사용자 LCP·INP·CLS를 확인했는가
  • 'use client' 경계가 페이지 전체로 넓어지지 않았는가
  • 번들 분석에서 큰 라이브러리와 중복 모듈을 확인했는가
  • LCP 이미지 한 개에만 preload를 적용했는가
  • 반응형 이미지에 정확한 sizes가 있는가
  • 공용 데이터와 사용자별 데이터를 다른 캐시 기준으로 나눴는가
  • 데이터 변경 후 revalidatePath 또는 태그 무효화 범위가 맞는가
  • 느린 데이터 영역을 Suspense로 나눌 수 있는가
  • 배포 리전·CDN·이미지 최적화·캐시 지속성을 운영 환경에서 확인했는가
  • 수정 전후 번들 크기와 Core Web Vitals를 같은 조건으로 비교했는가

FAQ

Q. Next.js 성능 최적화에서 가장 먼저 할 일은 무엇인가요?
실제 사용자 Core Web Vitals와 서버 응답, 번들 크기를 측정해 가장 큰 병목을 하나 고르는 일입니다. 측정 없이 이미지·캐시·메모이제이션을 동시에 바꾸면 어떤 수정이 효과가 있었는지 판단하기 어렵습니다.

Q. Next.js 16에서도 Image의 priority를 사용해도 되나요?
동작할 수는 있지만 Next.js 16에서는 priority가 deprecated 처리되어 preload 사용이 권장됩니다. 실제 LCP 후보에만 적용하세요.

Q. Vercel이 항상 가장 빠른가요?
Next.js 기능 통합은 편리하지만 모든 프로젝트에서 자동으로 가장 빠른 것은 아닙니다. 사용자와 서버의 거리, 데이터베이스 리전, 캐시 정책, 이미지 전송량과 비용까지 같은 조건으로 비교해야 합니다.

한 번의 변경을 평가하는 기록표

고정 조건수정 전수정 후
동일 URL·빌드모드·기기·네트워크같은 데이터 크기같은 데이터 크기
병목 후보LCP 이미지 요청 시작 지연이미지 전략 하나 변경
측정여러 회 실행의 중앙값·범위 기록같은 횟수로 반복
회귀CLS·전송량·입력 반응다른 지표 악화 확인

preload는 모든 LCP 상황의 기본 답이 아닙니다. Image의 loading=”eager” 또는 fetchPriority=”high”로 충분한 상황과 비교하고 preload와 loading/fetchPriority를 함께 지정하지 않습니다. 후보가 여러 개면 불필요한 선로드가 중요한 자원을 밀어낼 수 있습니다. 이 글은 성능 수치를 새로 측정하지 않았습니다.

공식 문서

공식 기준과 확인 범위

확인일: 2026-09-12. API 설명은 Next.js 16 App Router 기준이며 과거 릴리스 글은 본문의 태그 범위를 유지합니다. 부분 API 코드는 기존 프로젝트에 통합하는 예시입니다.

공식 자료 재확인: 2026-09-12. 이 글의 실행하지 않은 브라우저/배포 점검은 독자 확인 과제로 구분합니다.

이 글이 도움이 되었나요?

조회 중

Next.js 학습 순서

필수 13개 · 전체 27개

읽음 기록 관리

전체 과정 목차 (27개)
  1. 필수 길잡이 · Next.js App Router 학습 순서: 설치부터 배포까지
  2. 필수 학습 · Next.js package.json: scripts dependencies 이해
  3. 필수 학습 · Next.js App Router로 만드는 첫 프로젝트 완성 실습 가이드
  4. 필수 학습 · Next.js에서 .next 폴더는 어떤 역할을 할까?
  5. 필수 학습 · Next.js 동적 라우트 완전 정리: [slug], params, catch-all
  6. 선택 참고 · Next.js params should be awaited 해결: App Router 기준
  7. 선택 참고 · Next.js window is not defined 오류 해결: 브라우저 API를 안전하게 쓰기
  8. 선택 참고 · Next.js hydration failed 오류 해결: 원인과 해결 방법
  9. 필수 학습 · Axios 사용법: React Next.js에서 API 요청 구조 잡는 법
  10. 선택 참고 · Next.js Route Handler 405 오류 해결: GET/POST 파일 위치와 메서드 설정 확인
  11. 필수 학습 · Next.js Server Actions + React Hook Form 검증 기준
  12. 선택 참고 · Next.js useSearchParams Suspense 오류 해결: 빌드 실패 기준
  13. 선택 참고 · Next.js fetch 캐시 문제 해결: 데이터가 바뀌었는데 화면이 그대로일 때
  14. 선택 참고 · Next.js Dynamic server usage 오류 해결: cookies headers 기준
  15. 선택 참고 · Next.js 환경변수 적용 오류 해결: .env.local을 바꿨는데 값이 안 바뀔 때
  16. 필수 학습 · Next.js Metadata API 완전 정리: 정적 metadata와 generateMetadata
  17. 선택 참고 · Next.js metadata가 적용되지 않을 때 확인할 7가지
  18. 선택 참고 · Next.js Image remotePatterns 오류 해결: 외부 이미지 도메인 허용하기
  19. 필수 학습 · Next.js redirects 설정: next.config.js에서 URL 이동 처리
  20. 필수 학습 · Next.js SEO 체크리스트: metadata·초기 HTML·OG 이미지 점검
  21. 선택 참고 · Next.js SEO 완전 가이드: App Router metadata부터 배포 확인까지
  22. 필수 학습 · Next.js 16 성능 최적화 체크리스트: 번들·이미지·캐시·배포 현재 글
  23. 필수 학습 · Next.js 렌더링 성능 최적화: React 화면이 느릴 때 기준
  24. 필수 학습 · Next.js 16 Proxy 마이그레이션: Node.js Runtime·matcher 검증
  25. 선택 참고 · Next.js 보안 패치 기준: v16.2.5 영향 범위 점검
  26. 선택 참고 · Next.js SEO SSR 적용법: 검색 노출과 렌더링 구조 잡기
  27. 시점·기록 · Next.js 16.3.0-canary.106의 useCache deprecation 경고와 hybrid not-found 수정 이해하기

새 글 받아보기

RSS 리더에서 BlogFlow의 새 글을 확인할 수 있습니다.

RSS 피드 구독하기

댓글 남기기