본문으로 건너뛰기
코드룸CODE ROOMTENMO ↗

Next.js 이미지 최적화와 next/image 완벽 가이드

웹 페이지에서 이미지는 전체 리소스 크기의 가장 큰 비중을 차지합니다. 이미지만 잘 최적화해도 웹사이트 속도가 획기적으로 빨라지고, UX와 SEO 점수가 크게 올라갑니다.

Next.js는 이를 자동으로 처리해 주는 강력한 next/image 컴포넌트를 제공합니다.

일반 <img> 태그의 문제점과 최적화의 필요성

전통적인 <img> 태그를 그대로 사용하면 다음과 같은 성능 저하가 발생합니다.

  • 포맷 미최적화: PNG나 JPEG 같은 무거운 포맷을 그대로 서빙하여 대역폭을 낭비합니다. (WebP나 AVIF 같은 최신 포맷이 훨씬 가볍습니다.)

  • 크기 미최적화: 모바일 화면(모니터 크기 400px)에서도 4K 해상도(3840px)의 원본 이미지를 그대로 다운로드합니다.

  • Layout Shift: 이미지가 로드되면서 주변 텍스트나 레이아웃이 덜컥거리며 밀리는 현상이 발생해 사용자 경험을 해칩니다. (CLS 점수 저하)

  • Lazy Loading 부재: 당장 화면에 보이지 않는 페이지 맨 아래의 이미지까지 첫 페이지 로드 시 모두 다운로드합니다.

Next.js next/image가 자동으로 해결해 주는 것들

Next.js의 <Image /> 컴포넌트를 사용하면 코드 몇 줄로 아래 최적화가 기본 적용됩니다.

  1. 크기 최적화: 접속한 디바이스 크기에 맞는 적절한 사이즈의 이미지를 자동으로 생성하고 서빙합니다.

  2. 포맷 최적화: 브라우저가 지원하는 경우, 자동으로 더 가볍고 압축률이 높은 WebP 또는 AVIF 포맷으로 변환합니다.

  3. 레이아웃 유지: 이미지가 로드되기 전에 자리를 미리 확보하여 레이아웃이 깨지는 현상을 방지합니다.

  4. 지연 로딩: 뷰포트(화면)에 가까워진 이미지 만 선택적으로 로드하여 초기 페이지 로딩 속도를 올립니다.

로컬 이미지 vs 원격 이미지

next/image를 사용할 때는 이미지를 가져오는 출처에 따라 작성 방식이 약간 다릅니다.

① 로컬 이미지

public 폴더 내에 있거나 프로젝트 내부 파일을 직접 import하는 방식입니다. 이 경우 Next.js가 빌드 시점에 이미지의 widthheight를 자동으로 파악하므로 크기를 명시하지 않아도 됩니다.

import Image from 'next/image';
import profilePic from '../public/images/profile.png'; // 직접 import

export default function Page() {
  return (
    <div>
      <h1>내 프로필</h1>
      <Image
        src={profilePic}
        alt="Kukjin Lee 프로필 사진"
        // width, height를 적지 않아도 자동으로 계산됨
        placeholder="blur" // 로드 전 흐릿한 이미지 효과 (로컬 이미지 전용 기본 기능)
      />
    </div>
  );
}

② 원격 이미지

외부 CDN이나 API를 통해 가져오는 이미지 주소(https://...)를 사용할 때입니다. Next.js는 빌드 타임에 원격 이미지의 크기를 알 수 없기 때문에, 반드시 widthheight를 명시하거나 fill 속성을 사용해야 합니다.

import Image from 'next/image';

export default function Page() {
  return (
    <Image
      src="https://example.com/products/shoes-01.jpg"
      alt="러닝화 이미지"
      width={500}
      height={300}
    />
  );
}

⚠️ 중요 보안 설정 (next.config.js):

원격 이미지를 사용하려면 악의적인 외부 자원 요청을 방지하기 위해 반드시 허용할 도메인을 설정해야 합니다.

// next.config.js
const nextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'example.com',
        port: '',
        pathname: '/products/**',
      },
    ],
  },
};

module.exports = nextConfig;

실무에서 자주 쓰는 핵심 속성 (Props) 정리

속성 (Prop)

타입

설명

src

String / Object

이미지 경로 (필수)

alt

String

이미지를 설명하는 텍스트 (SEO 및 웹 접근성 필수)

width / height

Number

이미지의 화면 표시 크기 (픽셀 단위, fill 없을 때 필수)

fill

Boolean

부모 요소의 크기에 맞게 이미지를 꽉 채울 때 사용 (width/height 생략 가능)

sizes

String

미디어 쿼리에 따라 다운로드할 이미지 크기 힌트 제공 (성능 최적화 핵심)

priority

Boolean

true로 설정 시 지연 로딩을 끄고 가장 먼저 로드함 (LCP 이미지에 필수)

실무 팁: fillobject-fit 활용하기

반응형 웹을 만들다 보면 정해진 픽셀 크기가 아니라 부모 박스 크기에 맞춰 이미지가 늘어나거나 줄어들어야 할 때가 있습니다. 이때 fill 속성을 씁니다.

// 부모 박스에 반드시 position: relative 나 absolute 등이 있어야 합니다.
<div style={{ position: 'relative', width: '100%', height: '400px' }}>
  <Image
    src="/hero.jpg"
    alt="메인 배너"
    fill
    style={{ objectFit: 'cover' }} // CSS object-fit 속성과 함께 사용
  />
</div>

초보 개발자가 자주 하는 실수 & 체크리스트

첫 화면 배너 이미지(LCP)에 priority를 빼먹는 경우

  • 증상: 페이지를 열었을 때 메인 배너 이미지가 한참 뒤에 껌벅이며 나타남.

  • 해결책: 서비스의 첫인상을 좌우하는 가장 큰 이미지에는 priority 속성을 부여해 가장 먼저 다운로드하도록 만드세요.

    <Image src="/main-banner.jpg" alt="메인 배너" fill priority />
    

원격 이미지 크기 왜곡 현상

  • 증상: 원본 가로세로 비율과 next/image에 적어준 width, height 비율이 맞지 않아 이미지가 찌그러짐.

  • 해결책: CSS의 object-fit: cover 또는 contain을 적절히 조합하여 비율을 유지하게 제어합니다.

무조건 큰 sizes 설정 또는 생략 (fill 사용 시)

  • 증상: fill을 썼을 때 sizes 속성을 생략하면, Next.js는 뷰포트 100vw 전체 크기에 맞춘 초고해상도 이미지를 서빙하여 대역폭 낭비가 발생할 수 있습니다.

  • 해결책: 반응형 구간에 맞춰 다운로드할 크기 힌트를 명시하세요.

    // 모바일에선 100vw, 태블릿 이상에선 50vw 크기의 이미지만 다운로드해라!
    sizes="(max-width: 768px) 100vw, 50vw"
블로그 목록으로