Next.js Image Optimization (Images) 정리

Next.js Docs – Getting Started: Images (Image Optimization) 페이지를 기반으로, App Router 환경에서의 이미지 사용 및 최적화 방식을 정리한 문서입니다.


1. 개요

Next.js의 <Image> 컴포넌트는 기본 HTML <img> 요소를 확장하여 다음과 같은 기능을 제공합니다.

  • 크기 최적화 (Size optimization)
    • 기기별로 알맞은 크기의 이미지를 자동으로 제공하고, WebP 등 최신 포맷을 사용합니다.
  • 시각적 안정성 (Visual stability)
    • 이미지 로딩 중 레이아웃이 튀는 현상(Layout Shift, CLS)을 자동으로 방지합니다.
  • 더 빠른 페이지 로딩 (Faster page loads)
    • 뷰포트에 들어올 때만 이미지를 로드하는 브라우저 네이티브 lazy loading을 사용하고,
      선택적으로 블러(blur-up) 플레이스홀더를 제공합니다.
  • 유연한 에셋 관리 (Asset flexibility)
    • 원격(리모트) 서버에 있는 이미지도 필요할 때 크기를 변경하며 사용할 수 있습니다.

기본적인 사용은 다음과 같습니다.

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

export default function Page() {
  return <Image src="" alt="" />
}
  • src에는 로컬 이미지 경로 또는 원격 이미지 URL을 사용할 수 있습니다.

2. Local Images (로컬 이미지)

2.1 public 디렉터리 사용

정적인 파일(이미지, 폰트 등)은 프로젝트 루트에 있는 public 폴더 아래에 둘 수 있습니다.

my-app/
  app/
  public/
    profile.png
  • public 내부 파일은 기본 URL(/)을 기준으로 경로를 지정합니다.
// app/page.tsx
import Image from 'next/image'

export default function Page() {
  return (
    <Image
      src="/profile.png"
      alt="Picture of the author"
      width={500}
      height={500}
    />
  )
}
  • 여기서:
    • src="/profile.png"public/profile.png를 가리킴
    • width, height는 브라우저가 이미지 비율과 레이아웃을 미리 알 수 있도록 해 주어
      CLS(Cumulative Layout Shift)를 방지합니다.

2.2 정적 Import 사용

이미지를 정적으로 import 하면, Next.js가 빌드 시점에 해당 이미지의 intrinsic width / height와 블러 데이터(blurDataURL)를 자동으로 계산해 줍니다.

// app/page.tsx
import Image from 'next/image'
import ProfileImage from './profile.png'

export default function Page() {
  return (
    <Image
      src={ProfileImage}
      alt="Picture of the author"
      // width={500} 자동 제공
      // height={500} 자동 제공
      // blurDataURL="data:..." 자동 제공
      // placeholder="blur" // 로딩 중 블러 처리 (선택)
    />
  )
}
  • 정적 import를 사용하면:
    • width, height를 명시하지 않아도 됩니다.
    • blurDataURL이 자동 생성되어, placeholder="blur"만 추가해도 부드러운 블러 로딩 효과를 사용할 수 있습니다.
    • CLS 방지에 유리하고, 코드도 간결해집니다.

3. Remote Images (원격 이미지)

3.1 기본 사용

원격 이미지를 사용하려면 src절대 URL 문자열을 전달합니다.

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

export default function Page() {
  return (
    <Image
      src="https://s3.amazonaws.com/my-bucket/profile.png"
      alt="Picture of the author"
      width={500}
      height={500}
    />
  )
}
  • 원격 이미지는 빌드 시점에 파일에 접근할 수 없기 때문에,
    • 반드시 widthheight(또는 fill)를 명시해야 합니다.
    • 필요한 경우 **blurDataURL**도 직접 전달해야 합니다.

widthheight는 이미지의 가로세로 비율을 계산하는 데 사용되며,
로딩 중 레이아웃이 튀는 것을 방지하는 데 필수적입니다.

3.2 fill 속성 사용

정확한 픽셀 크기 대신, 부모 요소의 크기를 채우도록 만들고 싶다면 fill 속성을 사용할 수 있습니다.

// 예시: 부모 컨테이너를 기준으로 꽉 차게 렌더링
<div style={{ position: 'relative', width: 400, height: 300 }}>
  <Image
    src="https://s3.amazonaws.com/my-bucket/profile.png"
    alt="Picture of the author"
    fill
    style={{ objectFit: 'cover' }}
  />
</div>
  • 이 경우 부모 요소에 **고정된 width/height와 position: relative**가 설정되어 있어야 합니다.
  • <Image>는 내부적으로 position: absolute로 렌더링되어 부모를 채웁니다.

3.3 next.config.jsremotePatterns 설정

보안과 오용 방지를 위해, Next.js에서는 허용된 원격 이미지 도메인/경로를 명시적으로 지정해야 합니다.
이를 위해 next.config.js 또는 next.config.ts에서 images.remotePatterns를 설정합니다.

// next.config.ts
import type { NextConfig } from 'next'

const config: NextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 's3.amazonaws.com',
        port: '',
        pathname: '/my-bucket/**',
        search: '',
      },
    ],
  },
}

export default config
  • 위 설정은 다음과 같이 동작합니다.
    • 프로토콜: https
    • 호스트: s3.amazonaws.com
    • 경로: /my-bucket/** (특정 버킷 아래 경로만 허용)
    • 쿼리: search: '' (쿼리 스트링 없음)

보안을 위해 가능한 한 구체적인 패턴을 사용하는 것이 권장됩니다.
그렇지 않으면, 악의적인 사용자가 예기치 않은 도메인/경로의 이미지를 최적화 서버로 보내는 식으로 남용할 수 있습니다.


4. Image 컴포넌트가 제공하는 최적화 요약

Next.js next/image 컴포넌트는 다음과 같은 최적화를 자동으로 처리합니다.

  1. 크기 및 포맷 최적화

    • 뷰포트 크기, DPR(디바이스 픽셀 비율)에 따라 알맞은 이미지 크기를 제공
    • WebP 등의 최신 포맷을 자동으로 사용
  2. 레이아웃 안정성

    • width/height 또는 fill + 부모 컨테이너의 크기를 기반으로 레이아웃을 먼저 잡고 이미지를 로딩
    • CLS를 줄이는 데 큰 도움
  3. Lazy Loading

    • 뷰포트 외부의 이미지는 필요할 때까지 로딩하지 않음
    • 초기 페이지 로드 성능 향상
  4. Blur-up Placeholder (선택)

    • placeholder="blur"blurDataURL을 사용하면,
      저해상도 블러 이미지를 먼저 보여주고 이후 고해상도로 교체하는 패턴을 쉽게 구현 가능
  5. 로컬/원격 이미지 통합 관리

    • public 폴더 내부 정적 파일, 정적 import, 원격 URL 이미지를 모두 동일한 컴포넌트로 처리

자세한 속성 목록과 고급 기능은 Image Component API Reference에서 확인할 수 있습니다.