title: Next.js 애플리케이션 프로덕션 최적화 가이드 (How to optimize your Next.js application for production)
description: Next.js 애플리케이션을 실제 서비스(프로덕션)에 배포하기 전에 최고의 성능과 사용자 경험을 보장하기 위한 권장 사항들입니다.
url: "https://nextjs.org/docs/app/guides/production-checklist"
version: 16.1.6
lastUpdated: 2026-02-27
prerequisites:
Next.js 애플리케이션을 실제 서비스(프로덕션)에 배포하기 전에, 최고의 사용자 경험, 성능, 그리고 보안을 위해 몇 가지 최적화 기법과 패턴들을 적용하는 것을 꼭 고려해 보셔야 해요.
이 페이지는 여러분이 앱을 개발하는 동안 그리고 프로덕션에 배포하기 직전에 참고할 수 있는 모범 사례(Best Practices)들을 제공합니다. 또한, 여러분이 꼭 알아두셔야 할 Next.js의 자동 최적화 기능들에 대해서도 설명해 드릴게요.
아래에 설명할 Next.js의 최적화 기능들은 기본적으로 켜져 있어서 여러분이 따로 설정할 필요가 없습니다. 정말 편리하죠?
서버 컴포넌트 (Server Components): Next.js는 기본적으로 서버 컴포넌트를 사용해요. 서버 컴포넌트는 말 그대로 서버에서 실행되기 때문에, 클라이언트(브라우저)에서 렌더링하기 위한 JavaScript 파일이 필요하지 않아요. 즉, 사용자가 다운로드해야 하는 클라이언트 측 JavaScript 번들 크기에 전혀 영향을 주지 않는다는 뜻이죠. 상호작용(인터랙션)이 필요한 곳에만 필요에 따라 클라이언트 컴포넌트 (Client Components)를 섞어서 사용하시면 됩니다.
💡 강사 팁: 서버 컴포넌트는 프론트엔드 성능 최적화의 일등 공신이에요!
useState나useEffect같은 훅(Hook)은 서버 컴포넌트에서 쓸 수 없으니, 버튼 클릭 같은 이벤트가 필요한 최소한의 영역만 클라이언트 컴포넌트("use client")로 분리해서 트리 아래쪽으로 내리는 습관을 들여보세요.
코드 스플리팅 (Code-splitting): 서버 컴포넌트는 라우트 세그먼트별로 자동 코드 스플리팅을 지원합니다. 또한, 상황에 따라 클라이언트 컴포넌트나 서드파티 라이브러리를 지연 로딩 (lazy loading) 하는 것도 고려해 보세요.
💡 강사 팁: 무거운 차트 라이브러리나 당장 화면에 보이지 않는 모달 창 같은 건
next/dynamic을 사용해서 지연 로딩 처리를 해주면 초기 로딩 속도를 엄청나게 끌어올릴 수 있습니다.
프리패칭 (Prefetching): 새로운 라우트로 이동하는 링크(<Link>)가 사용자의 화면(뷰포트)에 들어오면, Next.js는 백그라운드에서 해당 라우트를 미리 가져옵니다(Prefetch). 덕분에 다른 페이지로 넘어갈 때 거의 즉시 이동하는 것처럼 느껴지게 되죠! 필요하다면 이 프리패칭 기능을 끌 수도 있어요.
💡 강사 팁: 한 화면에 게시물 링크가 100개씩 렌더링된다면 어떻게 될까요? 백그라운드에서 100개의 페이지를 미리 불러오느라 서버에 부담이 갈 수 있겠죠. 그럴 때는
<Link prefetch={false}>로 설정해서 마우스를 올렸을 때만 불러오도록 조절하는 센스가 필요합니다.
정적 렌더링 (Static Rendering): Next.js는 빌드할 때 서버와 클라이언트 컴포넌트를 서버에서 정적으로 렌더링하고, 애플리케이션의 성능을 높이기 위해 그 결과를 캐싱해 둡니다. 물론, 실시간 데이터가 필요한 특정 라우트에서는 동적 렌더링 (Dynamic Rendering)을 선택해서 사용할 수도 있어요.
캐싱 (Caching): Next.js는 데이터 요청, 서버/클라이언트 컴포넌트의 렌더링 결과, 정적 에셋(이미지 등) 등을 꼼꼼하게 캐싱합니다. 여러분의 서버, 데이터베이스, 백엔드 서비스로 가는 네트워크 요청 횟수를 획기적으로 줄여주죠. 필요하다면 특정 부분의 캐싱을 무효화하거나 제외할 수도 있습니다.
💡 강사 팁: 캐싱은 성능 향상의 핵심이지만, 초보자분들이 "어? DB 값을 바꿨는데 왜 화면이 안 바뀌지?" 하고 가장 많이 당황하는 부분이기도 해요.
revalidate옵션이나revalidatePath등을 통해 캐시 무효화 전략을 잘 짜는 것이 실력 있는 개발자의 필수 소양입니다.
이러한 기본 설정들은 애플리케이션의 전반적인 성능을 향상시키고, 각 네트워크 요청 시 전송되는 데이터의 양과 비용을 줄이는 데 목적을 두고 있어요.
애플리케이션을 한창 만들고 계실 때, 최고의 성능과 사용자 경험을 놓치지 않으려면 다음 기능들을 적극적으로 활용하시길 권장해 드려요.
<Link> 컴포넌트 (<Link> component): 클라이언트 측 네비게이션과 프리패칭을 위해 항상 <Link> 컴포넌트를 사용하세요. (일반 <a> 태그는 페이지 전체를 새로고침 해버리니까 조심하세요!)💡 강사 팁:
error.tsx와not-found.tsx는 사용자 경험을 지키는 최후의 보루입니다. 에러가 나도 사용자가 덜 당황하도록 귀여운 일러스트나 홈으로 돌아가기 버튼을 꼭 마련해 두세요!
"use client" 경계의 위치를 최대한 트리 아래쪽으로 내리는지 점검해 보셔야 합니다.cookies 함수나 searchParams 프롭(prop) 같은 동적 API를 사용하는 순간, 해당 라우트 전체가 동적 렌더링 (Dynamic Rendering)으로 전환된다는 사실을 명심하세요. (루트 레이아웃 (Root Layout)에서 쓰면 앱 전체가 동적으로 변해버릴 수도 있어요!) 동적 API 사용은 꼭 의도적으로 하셔야 하며, 적절한 곳은 <Suspense> 경계로 감싸주는 것이 좋습니다.알아두면 좋은 정보(Good to know): 부분 사전 렌더링(Partial Prerendering, 실험적 기능)을 사용하면 라우트 전체를 동적 렌더링으로 전환하지 않고도 라우트의 일부분만 동적으로 만들 수 있게 될 예정입니다.
💡 강사 팁: 이거 초보자분들이 정말 많이 하는 실수입니다. 서버 컴포넌트는 이미 서버 환경이기 때문에 API 엔드포인트를
fetch로 찌를 필요 없이, 데이터베이스 조회 함수나 백엔드 로직을 직접 호출하시면 됩니다.
loading.tsx)와 React Suspense를 활용해서 완성된 UI부터 서버에서 클라이언트로 점진적으로 보내주세요(Streaming).fetch 함수를 사용하지 않는 DB 쿼리 같은 요청들도 unstable_cache를 사용해서 캐싱할 수 있습니다.public 디렉토리를 사용하면 이미지 같은 애플리케이션의 정적 에셋들을 자동으로 캐싱할 수 있어요.app/global-error.tsx 파일을 추가하면, 앱 전체에서 잡히지 않은 최상위 에러가 발생했을 때 사용자에게 일관성 있고 접근성 좋은 폴백(fallback) UI와 복구 버튼을 제공할 수 있어요.app/global-not-found.tsx 파일을 추가해서, 앱 전체에서 일치하는 라우트가 없을 때 띄워줄 접근성 좋은 404 페이지를 만드세요.next/font)을 사용해 최적화하세요. 폰트 파일을 다른 정적 에셋들과 함께 자동으로 호스팅해주고, 외부 네트워크 요청을 없애주며, 텍스트가 늦게 뜨면서 화면이 밀리는 레이아웃 시프트(layout shift) 현상도 줄여줍니다.<Image> 컴포넌트 (<Image> Component): 일반 <img> 태그 대신 <Image> 컴포넌트를 사용해 이미지를 최적화하세요. 이미지를 자동으로 최적화하고, 레이아웃 시프트를 막아주며, WebP 같은 최신 용량 절감 포맷으로 이미지를 제공해 줍니다.💡 강사 팁:
<Image>를 쓸 때 레이아웃 시프트를 방지하려면width와height값을 꼭 지정해 주거나, 부모 요소에 맞춰지는fill속성을 활용하셔야 해요. 외부 URL의 이미지를 쓸 땐next.config.js에 해당 도메인을 등록해 주는 것도 절대 잊지 마세요!
<Script> 컴포넌트 (<Script> Component): 구글 애널리틱스 같은 서드파티 스크립트를 넣을 땐 <Script> 컴포넌트로 최적화하세요. 스크립트를 자동으로 지연시켜서 브라우저의 메인 스레드를 막지 않게 해줍니다.eslint-plugin-jsx-a11y 플러그인을 활성화해서, 웹 접근성 문제를 개발 초기에 미리미리 잡아내세요..env.* 파일들은 무조건 .gitignore에 추가해서 깃허브에 올라가지 않도록 막고, 클라이언트(브라우저)에서 접근해야 하는 퍼블릭 변수에만 NEXT_PUBLIC_ 접두사를 붙이세요.💡 강사 팁: 이거 정말정말 중요한 팁입니다! 결제 API 시크릿 키나 DB 비밀번호 같은 것에 실수로
NEXT_PUBLIC_을 붙이면 브라우저 소스코드에 비밀번호가 그대로 노출됩니다. 무조건 서버에서만 쓸 변수에는 접두사를 붙이지 마세요!
실제 서비스로 배포하기 직전에, 터미널에서 next build 명령어를 실행해 로컬 환경에서 앱을 빌드해 보세요. 빌드 에러가 없는지 확실히 잡고 넘어갈 수 있습니다. 그 다음 next start 명령어로 실행하면, 실제 프로덕션과 거의 똑같은 환경에서 애플리케이션의 진짜 성능을 측정해 볼 수 있습니다. (개발 모드인 next dev 때보다 훨씬 빠르답니다!)
💡 강사 팁: 왜 꼭 시크릿 모드에서 해야 할까요? 우리가 평소에 쓰는 크롬 확장프로그램(광고 차단기, 번역기 등)이 페이지 렌더링에 간섭해서 라이트하우스 점수를 깎아먹을 수 있거든요. 정확한 측정을 위해선 꼭 시크릿 모드로 켜주세요!
useReportWebVitals 훅 (useReportWebVitals hook): 이 훅을 사용하면 앱의 코어 웹 바이탈(Core Web Vitals) 지표 데이터를 수집해서 구글 애널리틱스 같은 분석 도구로 보낼 수 있습니다.프론트엔드 최적화의 꽃은 번들 다이어트죠! @next/bundle-analyzer 플러그인을 사용해서 여러분이 빌드한 JavaScript 번들의 크기를 시각적으로 분석해 보세요. 애플리케이션 성능을 깎아먹고 있는 용량 큰 모듈이나 외부 의존성(라이브러리)을 쉽게 찾아낼 수 있습니다.
💡 강사 팁: 이 애널라이저 화면을 띄워놓고 보면 정말 놀라실 거예요. "내가 쓰지도 않는 라이브러리가 이렇게 크게 들어가 있었다고?" 하면서 불필요한 코드를 덜어내는 재미가 쏠쏠합니다.
그 외에도, 프로젝트에 새로운 라이브러리(의존성)를 추가할 때 그게 앱 용량에 어떤 영향을 미칠지 미리 알려주는 유용한 도구들이 있어요. 한 번 활용해 보세요:
모든 공식 문서의 의미론적 개요(Semantic overview)를 보시려면, https://nextjs.org/docs/sitemap.md 를 참고해 주세요.
이용 가능한 모든 공식 문서의 전체 색인(Index)을 보시려면, https://nextjs.org/docs/llms.txt 를 참고해 주세요.