Optimizing package bundling

김동현·2026년 3월 5일

next.js 공식문서 번역

목록 보기
56/79

안녕하세요! 여러분의 프론트엔드 성장을 돕는 강사입니다.

오늘은 Next.js 공식 문서 중 성능 최적화의 핵심인 '패키지 번들링 최적화(Optimizing package bundling)' 파트를 함께 씹어먹어 볼 거예요. 특히 여러분이 앞으로 만들게 될 벨로그 스타일의 블로그 뷰어나 AI 기반 문서 번역기처럼 데이터를 많이 다루거나 무거운 라이브러리를 쓰는 포트폴리오 프로젝트에서 이 번들링 최적화는 선택이 아닌 필수랍니다. 게다가 최근 기술 면접에서도 "웹 성능 최적화 경험이 있나요?"라는 질문은 단골 손님이니까, 오늘 내용을 잘 숙지해 두면 면접장에서도 엄청난 무기가 될 거예요.

딱딱한 직역보다는 우리가 실무에서 쓰는 자연스러운 말투로, 그리고 제 실무 경험과 팁까지 듬뿍 담아서 설명해 드릴게요. 자, 시작해 볼까요?


패키지 번들링 최적화 (Optimizing package bundling)

설명: Turbopack용 Next.js Bundle Analyzer와 Webpack용 @next/bundle-analyzer 플러그인을 사용하여 애플리케이션의 서버 및 클라이언트 번들을 분석하고 최적화하는 방법을 배워보세요.
URL: https://nextjs.org/docs/app/guides/package-bundling
버전: 16.1.6
최종 업데이트: 2026-02-27
선수 지식:


번들링(Bundling)은 여러분이 작성한 애플리케이션 코드와 그 코드가 의존하고 있는 패키지들을 클라이언트와 서버 환경에 맞게 최적화된 결과물 파일로 하나로 합치는 과정을 말해요. 번들 크기가 작아지면 로딩 속도도 빨라지고, 자바스크립트 실행 시간도 줄어들며, 결과적으로 Core Web Vitals (핵심 웹 바이탈) 지표가 개선되고 서버의 콜드 스타트 시간도 단축됩니다.

💡 강사의 팁: > 여기서 말하는 '콜드 스타트(Cold Start)'는 서버리스 환경(예: Vercel 등)에서 함수가 처음 호출될 때 컨테이너를 띄우고 준비하는 데 걸리는 시간을 말해요. 번들이 무거우면 이 준비 시간이 길어져서 첫 사용자가 엄청난 지연을 겪게 되죠. 프론트엔드 개발자라면 Lighthouse 같은 도구로 Core Web Vitals(LCP, FID 등)를 측정해보는 습관을 들이는 것이 좋습니다!

Next.js는 기본적으로 코드 스플리팅(Code splitting), 트리 쉐이킹(Tree-shaking) 같은 기술을 사용해서 번들을 자동으로 최적화해 줍니다. 하지만 때로는 우리가 직접 수동으로 번들을 최적화해야 하는 경우도 생겨요.

애플리케이션의 번들을 분석할 수 있는 도구는 크게 두 가지가 있습니다:

이 가이드에서는 각 도구를 사용하는 방법과 거대한 번들을 최적화하는 방법에 대해 차근차근 알아볼 거예요.

Next.js Bundle Analyzer (실험적 기능)

v16.1 및 이후 버전에서 사용할 수 있습니다. 전용 GitHub 토론 페이지에서 피드백을 공유하실 수 있으며, turbopack-bundle-analyzer-demo.vercel.sh에서 데모를 확인해 보세요.

💡 강사의 부연 설명:
Turbopack(터보팩)은 기존 Webpack을 대체하기 위해 Rust 언어로 만들어진 엄청나게 빠른 번들러예요. Next.js가 적극적으로 밀고 있는 기술이죠. 이 터보팩 전용 분석기가 최근에 도입되었습니다.

Next.js Bundle Analyzer는 Turbopack의 모듈 그래프와 통합되어 있습니다. 서버와 클라이언트 모듈을 정밀한 임포트 추적(import tracing) 기능을 통해 검사할 수 있어서, 용량을 많이 차지하는 무거운 의존성 패키지를 쉽게 찾아낼 수 있어요. 대화형(interactive) Bundle Analyzer 데모를 열어서 모듈 그래프를 직접 탐색해 보세요.

1단계: Turbopack Bundle Analyzer 실행하기

시작하려면 터미널에서 아래 명령어를 실행하고, 브라우저에서 대화형 뷰(interactive view)를 열어보세요.

npx next experimental-analyze
yarn next experimental-analyze
pnpm next experimental-analyze
bunx next experimental-analyze

2단계: 모듈 필터링 및 검사하기

UI 화면 내에서 라우트(경로), 환경(클라이언트 또는 서버), 그리고 타입(JavaScript, CSS, JSON)별로 필터링하거나 파일 이름으로 검색할 수 있습니다.

3단계: 임포트 체인을 통한 모듈 추적

트리맵(Treemap)은 각각의 모듈을 직사각형으로 보여줍니다. 직사각형의 넓이가 곧 해당 모듈의 크기를 나타내죠.

모듈을 클릭하면 해당 모듈의 크기를 확인하고, 전체 임포트 체인을 검사하여 우리 애플리케이션의 어느 부분에서 정확히 사용되고 있는지 확인할 수 있습니다:

번들 분석기 예시 이미지

4단계: 공유나 비교를 위해 결과를 디스크에 저장하기

만약 팀원들과 분석 결과를 공유하고 싶거나, 최적화 전/후의 번들 크기를 비교하고 싶다면 --output 플래그를 붙여서 대화형 뷰를 건너뛰고 분석 결과를 정적 파일로 저장할 수 있습니다:

npx next experimental-analyze --output
yarn next experimental-analyze --output
pnpm next experimental-analyze --output
bunx next experimental-analyze --output

이 명령어를 실행하면 .next/diagnostics/analyze 경로에 결과물이 저장됩니다. 이 폴더를 다른 곳으로 복사해서 나중에 결과를 비교할 때 쓸 수 있어요:

cp -r .next/diagnostics/analyze ./analyze-before-refactor

Bundle Analyzer에 사용할 수 있는 더 많은 옵션들이 있습니다. 전체 목록은 Next.js CLI 참조 문서를 확인해 주세요.

Webpack용 @next/bundle-analyzer

💡 강사의 부연 설명:
터보팩이 아닌 기존 웹팩(Webpack) 환경을 사용 중이라면 이 방법을 쓰시면 됩니다. 실무에서는 아직 웹팩 기반으로 돌아가는 레거시 프로젝트도 많기 때문에 이 플러그인 사용법도 반드시 알아두셔야 해요.

@next/bundle-analyzer는 애플리케이션 번들 크기를 관리하는 데 도움을 주는 플러그인입니다. 각 패키지와 그 의존성들의 크기를 시각적인 리포트로 생성해 주죠. 이 정보를 바탕으로 무거운 의존성을 제거하거나, 코드를 분할(split)하거나, 지연 로딩(lazy-load)을 적용할 수 있습니다.

1단계: 설치하기

다음 명령어를 실행해서 플러그인을 설치해 주세요:

pnpm add @next/bundle-analyzer
npm install @next/bundle-analyzer
yarn add @next/bundle-analyzer
bun add @next/bundle-analyzer

그런 다음, 번들 분석기 설정을 next.config.js 파일에 추가해 줍니다.

/** @type {import('next').NextConfig} */
const nextConfig = {}

const withBundleAnalyzer = require('@next/bundle-analyzer')({
  enabled: process.env.ANALYZE === 'true',
})

module.exports = withBundleAnalyzer(nextConfig)

💡 강사의 팁:
여기서 process.env.ANALYZE === 'true' 부분이 핵심이에요. 평소 개발할 때나 배포할 때는 분석기가 돌지 않게 하고, 오직 우리가 터미널에서 ANALYZE=true라는 환경 변수를 줬을 때만 작동하게 만드는 안전장치랍니다.

2단계: 리포트 생성하기

다음 명령어를 실행하여 번들을 분석해 보세요:

ANALYZE=true npm run build
# 또는
ANALYZE=true yarn build
# 또는
ANALYZE=true pnpm build

명령어가 완료되면 브라우저에 세 개의 새로운 탭이 열리며, 여기서 리포트를 살펴볼 수 있습니다. (주로 클라이언트 번들, 엣지 번들, 노드 서버 번들 화면이 열립니다.)

큰 용량의 번들 최적화하기 (Optimizing large bundles)

용량을 많이 차지하는 모듈을 찾아냈다면, 어떻게 해결할지는 여러분의 사용 사례에 따라 달라집니다. 아래에 실무에서 흔히 발생하는 원인들과 그 해결 방법을 정리해 드릴게요:

수많은 export를 가진 패키지들

아이콘 라이브러리나 유틸리티 라이브러리처럼 수백 개의 모듈을 export 하는 패키지를 사용할 때, next.config.js 파일의 optimizePackageImports 옵션을 사용하면 이런 임포트가 해석되는 방식을 최적화할 수 있습니다. 이 옵션을 쓰면 수많은 named export(이름 있는 내보내기)를 사용해서 코드를 편하게 작성하면서도, 실제로는 여러분이 진짜로 사용하는 모듈만 로드하게 됩니다.

/** @type {import('next').NextConfig} */
const nextConfig = {
  experimental: {
    optimizePackageImports: ['icon-library'],
  },
}

module.exports = nextConfig

알아두면 좋은 점: Next.js는 이미 일부 유명 라이브러리들을 자동으로 최적화하고 있습니다. 그래서 그 패키지들은 optimizePackageImports 목록에 따로 넣을 필요가 없어요. 기본적으로 지원되는 패키지들의 전체 목록을 확인해 보세요.

💡 강사의 팁: 이거 정말 중요합니다! 보통 import { UserIcon } from 'lucide-react' 처럼 쓰면, 설정이 안 되어 있을 경우 lucide-react의 전체 아이콘이 다 번들에 딸려 들어오는 대참사(이른바 배럴 파일 문제)가 발생할 수 있어요. Next.js가 이걸 방지해주는 기능입니다.

무거운 클라이언트 작업 처리 (Heavy client workloads)

클라이언트 번들 크기가 커지는 가장 흔한 원인 중 하나는 '클라이언트 컴포넌트(Client Components)' 안에서 렌더링 비용이 많이 드는 무거운 작업을 하는 것입니다. 문법 하이라이팅(Syntax highlighting), 차트 렌더링, 또는 마크다운 파싱 같이 단순히 데이터를 UI로 변환하기 위해 존재하는 라이브러리들을 쓸 때 이런 일이 자주 발생하죠.

만약 그 작업이 브라우저의 API(예: window, document)나 사용자의 상호작용(onClick 등)을 필요로 하지 않는다면, 서버 컴포넌트(Server Component)에서 실행하는 것이 훨씬 좋습니다.

아래 예시를 볼까요? Prism(프리즘) 기반의 코드 하이라이터가 클라이언트 컴포넌트에서 실행되고 있습니다. 최종 결과물은 그저 단순한 <code> HTML 블록일 뿐인데도 불구하고, 방대한 크기의 하이라이팅 라이브러리 전체가 클라이언트 자바스크립트 번들에 포함되어 유저에게 전송되어 버립니다:

'use client'

import Highlight from 'prism-react-renderer'
import theme from 'prism-react-renderer/themes/github'

export default function Page() {
  const code = `export function hello() {
    console.log("hi")
  }`

  return (
    <article>
      <h1>Blog Post Title</h1>

      {/* prism 패키지와 그 토크나이징 로직 전체가 클라이언트에게 전송됩니다! */}
      <Highlight code={code} language="tsx" theme={theme}>
        {({ className, style, tokens, getLineProps, getTokenProps }) => (
          <pre className={className} style={style}>
            <code>
              {tokens.map((line, i) => (
                <div key={i} {...getLineProps({ line })}>
                  {line.map((token, key) => (
                    <span key={key} {...getTokenProps({ token })} />
                  ))}
                </div>
              ))}
            </code>
          </pre>
        )}
      </Highlight>
    </article>
  )
}

결과물이 정적인 HTML임에도 불구하고 클라이언트가 무거운 하이라이팅 라이브러리를 직접 다운로드하고 브라우저에서 실행해야 하므로 번들 크기가 엄청나게 늘어납니다.

대안: 하이라이팅 로직을 서버 컴포넌트로 옮기고 최종 HTML을 서버에서 렌더링하세요. 그러면 클라이언트는 복잡한 JS 코드 없이 깔끔하게 렌더링된 순수 마크업(HTML)만 받게 됩니다.

import { codeToHtml } from 'shiki'

export default async function Page() {
  const code = `export function hello() {
    console.log("hi")
  }`

  // Shiki 패키지는 서버에서만 실행되며, 클라이언트 번들에는 절대 포함되지 않습니다.
  const highlightedHtml = await codeToHtml(code, {
    lang: 'tsx',
    theme: 'github-dark',
  })

  return (
    <article>
      <h1>Blog Post Title</h1>

      {/* 클라이언트는 무거운 JS 없이 순수한 HTML 마크업만 전달받습니다! */}
      <pre>
        <code dangerouslySetInnerHTML={{ __html: highlightedHtml }} />
      </pre>
    </article>
  )
}

💡 강사의 특급 팁:
AI 문서 번역기나 기술 블로그 뷰어 포트폴리오를 만드실 때 이 패턴을 적극적으로 도입해 보세요. 사용자는 번역된 내용이나 코드를 '읽기만' 하면 되죠? 굳이 그 파싱 과정을 브라우저(클라이언트)에서 할 필요가 없습니다. 서버에서 shiki나 마크다운 파서로 다 파싱해서 HTML만 브라우저로 쏴주세요. 로딩 속도가 체감될 정도로 확연히 달라집니다. 이게 바로 Next.js App Router의 핵심 철학이에요!

특정 패키지를 번들링에서 제외하기

서버 컴포넌트와 라우트 핸들러(Route Handlers) 내부에서 임포트된 패키지들은 Next.js에 의해 자동으로 번들링됩니다.

하지만 next.config.js 파일에서 serverExternalPackages 옵션을 사용하면 특정 패키지를 번들링 과정에서 완전히 제외(opt out)시킬 수 있습니다.

/** @type {import('next').NextConfig} */
const nextConfig = {
  serverExternalPackages: ['package-name'],
}

module.exports = nextConfig

💡 강사의 팁:
보통 언제 이걸 쓸까요? Node.js 환경에서만 돌아가야 하는 네이티브 바이너리 모듈(예: C++ 기반으로 작성되어 컴파일이 필요한 패키지나 데이터베이스 드라이버 등)을 사용할 때 주로 씁니다. 이런 애들은 억지로 Webpack이나 Turbopack으로 번들링하려고 하면 에러가 나거든요. 그럴 때 "얘는 번들링하지 말고 그냥 Node.js 모듈로 냅둬!"라고 설정해 주는 거예요.


프로덕션 환경을 위해 애플리케이션을 최적화하는 방법에 대해 더 자세히 알아보세요.

  • 프로덕션 (Production)
    • Next.js 애플리케이션을 실제 서비스(프로덕션)에 배포하기 전에 최상의 성능과 사용자 경험을 보장하기 위한 권장 사항들을 확인하세요.

모든 문서의 의미론적 개요를 보려면 /docs/sitemap.md를 참조하세요.

사용 가능한 모든 문서의 색인을 보려면 /docs/llms.txt를 참조하세요.


자, 여기까지 꼼꼼하게 공식 문서를 번역하고 제 팁도 얹어드렸습니다. 프론트엔드 개발자는 단순히 화면을 예쁘게 그리는 것을 넘어, 어떻게 하면 사용자에게 단 0.1초라도 더 빠르게 화면을 보여줄 수 있을까 고민하는 직업입니다. 번들 분석기를 직접 프로젝트에 띄워보시고 무거운 패키지들을 하나씩 덜어내는 쾌감을 꼭 느껴보시길 바랍니다! 포트폴리오 준비와 취업 준비 모두 응원합니다! 파이팅!

profile
프론트에_가까운_풀스택_개발자

0개의 댓글