Published on

Next.js 이미지 LCP 개선 - next/image 최적화

Authors

서버/클라이언트 렌더링이 아무리 빨라도, 히어로 이미지 한 장이 늦게 뜨면 LCP(Largest Contentful Paint)는 그대로 무너집니다. 특히 Next.js에서 next/image를 “그냥 Image로 바꿔 끼우는 수준”에서 끝내면, 오히려 잘못된 sizes나 레이아웃 선택 때문에 다운로드 바이트가 늘거나 프리로드가 실패해 LCP가 악화되는 경우도 흔합니다.

이 글은 Next.js에서 LCP에 영향을 주는 이미지 경로를 분해하고, next/image의 옵션을 어떤 순서로 점검해야 실제로 LCP가 내려가는지(그리고 왜 내려가는지)를 코드 중심으로 정리합니다.

LCP와 이미지: 어디서 시간이 새는가

이미지 LCP는 대체로 아래 구간의 합으로 결정됩니다.

  1. HTML 도착 및 파싱
  2. LCP 후보(대개 히어로 이미지) 리소스 발견
  3. 네트워크 요청 시작(프리로드 여부가 큼)
  4. 다운로드(바이트 수, CDN, 캐시)
  5. 디코딩 및 렌더(레이아웃 안정성 포함)

next/image는 2~5를 건드립니다. 하지만 “자동 최적화”라는 말만 믿고 기본값을 쓰면, 3번(요청 시작)이 늦어지거나 4번(다운로드)이 커질 수 있습니다. LCP 개선은 결국 다음 3가지로 귀결됩니다.

  • 요청을 더 빨리 시작: priority와 프리로드
  • 필요한 만큼만 다운로드: 올바른 sizes, 적절한 quality, 최신 포맷
  • 렌더링 비용과 레이아웃 흔들림 제거: fill/width/height 선택, CSS

1) 히어로 이미지는 반드시 우선 로딩으로 고정하기

히어로 이미지가 LCP라면, 해당 이미지는 지연 로딩(lazy)되면 안 됩니다. next/image에서 핵심은 priority입니다.

App Router 예시: 히어로 이미지에 priority 적용

// app/page.tsx
import Image from 'next/image'

export default function Page() {
  return (
    <main>
      <section style={{ position: 'relative', height: 420 }}>
        <Image
          src="/images/hero.jpg"
          alt="Product hero"
          fill
          priority
          sizes="(max-width: 768px) 100vw, 1200px"
          style={{ objectFit: 'cover' }}
        />
      </section>
    </main>
  )
}
  • priority는 내부적으로 프리로드 힌트를 생성해 “리소스 발견 및 요청 시작”을 앞당깁니다.
  • LCP 후보가 명확한 경우 priority는 거의 필수입니다.

주의: priority는 1개(또는 아주 소수)만

priority를 여러 이미지에 남발하면 프리로드 경쟁이 생겨 오히려 LCP가 느려질 수 있습니다. 원칙은 “LCP 후보 1개”에만 적용하고, 나머지는 기본 lazy로 두는 것입니다.

2) sizes를 틀리게 쓰면 LCP가 악화된다

next/imagesrcset을 만들어 다양한 해상도 이미지를 제공하지만, 브라우저가 “어떤 크기를 받을지”를 결정하는 열쇠는 sizes입니다.

  • sizes가 없거나 부정확하면 브라우저가 큰 이미지를 선택할 가능성이 커집니다.
  • 특히 fill을 쓰면서 sizes="100vw"로 고정해버리면, 데스크톱에서도 뷰포트 전체 폭으로 계산되어 불필요하게 큰 파일을 받는 일이 잦습니다.

흔한 실수: 무조건 100vw

<Image
  src="/images/hero.jpg"
  alt="Hero"
  fill
  priority
  sizes="100vw"
/>

히어로가 실제로는 컨테이너 최대 폭 1200px인데 100vw로 선언하면, 1920px급 리소스를 고르는 식의 과다운로드가 발생할 수 있습니다.

권장 패턴: 브레이크포인트와 최대 폭을 함께 선언

<Image
  src="/images/hero.jpg"
  alt="Hero"
  fill
  priority
  sizes="(max-width: 768px) 100vw, (max-width: 1200px) 90vw, 1200px"
/>
  • 모바일: 뷰포트 폭만큼
  • 태블릿/중간: 90vw
  • 데스크톱: 최대 1200px로 캡

이 한 줄이 LCP 바이트를 수십 퍼센트 줄이는 경우가 많습니다.

3) 레이아웃 선택: fill vs width/height 그리고 CLS

LCP는 “언제 그려지느냐”뿐 아니라 “그릴 때 레이아웃이 안정적인가”도 영향을 받습니다. 이미지가 그려지는 순간 레이아웃이 튀면, 브라우저는 추가 작업을 하게 됩니다.

원칙

  • 고정 비율 카드/썸네일: width/height로 명시하는 편이 단순하고 안정적
  • 배경형 히어로(컨테이너에 꽉 차는): fill + 부모에 position: relative와 명확한 높이
// 카드 썸네일 예시
<Image
  src="/images/thumb.jpg"
  alt="Thumbnail"
  width={360}
  height={240}
  sizes="(max-width: 768px) 50vw, 360px"
/>

width/height를 주면 브라우저가 공간을 미리 확보하므로 CLS가 줄고, 렌더링 파이프라인이 단순해집니다.

렌더링 영역 최적화 관점에서는 이미지 주변 레이아웃도 중요합니다. 이미지 외 컨텐츠가 많아 메인 스레드가 바쁘면 LCP가 늦어질 수 있으니, 필요하다면 CSS 렌더링 튜닝도 함께 보세요: CSS contain·content-visibility로 렌더링 튜닝

4) 포맷과 품질: “가볍게”가 아니라 “맞게”

quality는 기본값에만 맡기지 말고 측정 기반으로

히어로 이미지는 품질을 너무 낮추면 밴딩/블러가 눈에 띄지만, 너무 높이면 LCP 바이트가 늘어납니다. 보통은 다음처럼 시작해 측정으로 조정합니다.

<Image
  src="/images/hero.jpg"
  alt="Hero"
  fill
  priority
  quality={75}
  sizes="(max-width: 768px) 100vw, 1200px"
/>
  • 사진: quality 70~80에서 타협점이 자주 나옵니다.
  • 일러스트/텍스트 포함 이미지: 품질을 더 높이거나(혹은 SVG/벡터로 대체) 접근해야 합니다.

최신 포맷: AVIF/WebP를 제대로 쓰고 있는지

Next.js의 이미지 최적화는 보통 자동으로 WebP/AVIF를 협상합니다. 다만, 원본이 지나치게 큰 PNG이거나, CDN/프록시가 헤더를 망가뜨리면 협상이 실패하기도 합니다.

운영에서 캐시/재검증이 꼬이면 “이미지가 계속 새로 최적화되거나 캐시가 안 먹는” 형태로 LCP가 튈 수 있습니다. App Router의 캐시 동작을 함께 점검하려면 이 글도 도움이 됩니다: Next.js App Router 캐시 꼬임·재검증 버그 해결

5) next.configimages 설정: 원격 이미지와 캐시를 통제

외부 이미지(예: CMS, S3, 이미지 CDN)를 쓸 때는 remotePatterns를 명시하고, 가능하면 CDN을 통해 지연과 변동성을 줄입니다.

// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'cdn.example.com',
        pathname: '/images/**',
      },
    ],
    formats: ['image/avif', 'image/webp'],
  },
}

module.exports = nextConfig

추가로, 원격 서버의 응답 헤더가 캐시에 불리하면(짧은 cache-control, vary 문제 등) LCP가 흔들립니다. CDN에서 적절한 TTL과 캐시 키 정책을 잡는 것이 중요합니다.

6) 블러 플레이스홀더는 “체감”엔 좋지만 LCP엔 독이 될 수 있다

placeholder="blur"는 초기 페인트를 부드럽게 해주지만, 히어로 이미지에 남발하면 다음 문제가 생길 수 있습니다.

  • 블러 데이터 생성/전송 비용
  • 메인 이미지 로딩 자체가 빨라지는 것은 아님

히어로(LCP 후보)에는 보통 priority와 правиль한 sizes가 우선이고, blur는 체감 품질이 필요할 때만 제한적으로 사용합니다.

<Image
  src="/images/thumb.jpg"
  alt="Thumb"
  width={360}
  height={240}
  placeholder="blur"
  blurDataURL="data:image/jpeg;base64,..."
/>

7) 실전 점검 체크리스트: LCP가 안 내려갈 때

(1) LCP 후보가 정말 그 이미지가 맞는지

Chrome DevTools의 Performance/웹 바이탈 오버레이로 LCP 엘리먼트를 확인합니다. 텍스트 블록이 LCP인 경우도 많습니다.

(2) priority가 적용되었는지

  • LCP 이미지에 priority가 있는가
  • 동시에 priority 이미지가 여러 개는 아닌가

(3) sizes가 실제 레이아웃과 일치하는지

  • 컨테이너 최대 폭을 반영했는가
  • 모바일/태블릿/데스크톱 브레이크포인트가 합리적인가

(4) 과다운로드 여부

  • 네트워크 탭에서 실제로 내려받는 이미지 픽셀 폭이 과한지 확인
  • 필요하면 sizes를 더 공격적으로 캡

(5) 서버/캐시 문제로 이미지가 매번 느린지

  • 원격 이미지 응답이 느린가
  • CDN 캐시 히트가 나는가
  • App Router 캐시/재검증이 이미지 경로에 영향을 주는가

8) 예시: 히어로와 리스트를 분리 최적화하기

히어로 1장은 LCP를 위해 최우선, 아래 리스트 썸네일은 지연 로딩과 정확한 sizes로 바이트를 줄입니다.

import Image from 'next/image'

export function Hero() {
  return (
    <header style={{ position: 'relative', height: 460 }}>
      <Image
        src="https://cdn.example.com/images/hero-2026.jpg"
        alt="Main hero"
        fill
        priority
        sizes="(max-width: 768px) 100vw, 1200px"
        quality={78}
        style={{ objectFit: 'cover' }}
      />
      <h1 style={{ position: 'relative' }}>Next.js 성능 튜닝</h1>
    </header>
  )
}

export function Card({ src, title }: { src: string; title: string }) {
  return (
    <article>
      <Image
        src={src}
        alt={title}
        width={320}
        height={200}
        sizes="(max-width: 768px) 50vw, 320px"
      />
      <h2>{title}</h2>
    </article>
  )
}
  • 히어로: fill + priority + 최대 폭 1200px
  • 카드: 고정 크기 + lazy(기본) + 모바일에서만 50vw

마무리: LCP는 “옵션 몇 개”가 아니라 경로 최적화다

next/image는 LCP 개선의 강력한 도구지만, 핵심은 자동 최적화가 아니라 “브라우저가 올바른 순간에, 올바른 크기의 이미지를 받게 만드는 것”입니다. 실전에서 가장 효과가 큰 순서는 대개 다음과 같습니다.

  1. LCP 이미지에 priority
  2. sizes를 실제 레이아웃에 맞게 수정(최대 폭 캡)
  3. 레이아웃 안정화(fill 사용 시 부모 높이/포지션 명확화)
  4. 품질/포맷/캐시 점검

이 4가지만 제대로 맞춰도, 히어로 이미지가 LCP인 페이지는 체감과 지표가 함께 개선되는 경우가 많습니다.