Develop
Next.js Image 컴포넌트로 이미지를 최적화하는 방법 — WebP 자동 변환과 lazy loading
img 태그 대신 Next.js Image 컴포넌트를 쓰면 WebP 자동 변환, lazy loading, 레이아웃 시프트 방지가 한 번에 해결된다. width/height 지정, fill 모드, 외부 이미지 도메인 허용까지 정리했다.

- ·Next.js Image 컴포넌트: 자동 WebP/AVIF 변환, lazy loading, srcset 자동 생성
- ·CLS(Cumulative Layout Shift): width/height 미지정 시 이미지 로드 전후 레이아웃 이동 발생
- ·fill 모드: 부모 컨테이너 크기를 채우는 방식, 부모에 position: relative 필요
- ·remotePatterns: next.config에서 외부 이미지 도메인을 명시적으로 허용해야 함
초기에 블로그 메인 화면의 첫 로딩 Lighthouse 성능 점수가 70점대에 머물러서 좌절했던 적이 있습니다. 범인은 다름 아닌 원본 크기 그대로 박혀 있던 무거운 PNG 파일들이었는데, 이를 `<Image>` 컴포넌트로 마이그레이션하자마자 별다른 삽질 없이 한 번에 WebP 자동 변환과 lazy loading이 적용되어 점수가 90점대 후반으로 수직 상승하는 마법 같은 경험을 했습니다. 다만 페이지 최상단 히어로 썸네일 이미지에 `priority` 주는 걸 빼먹어서 한동안 LCP(최대 콘텐츠 렌더링 시간) 지표가 잘 안 나왔는데, 이 속성 하나 추가하는 것만으로 로딩 체감이 눈에 띄게 개선되었습니다.
1. 모던 웹 성능 향상을 위한 이미지 최적화
구형 img 태그의 한계와 Next.js Image 컴포넌트 도입의 이점
전통적인 HTML의 <img> 태그를 이용해 웹사이트에 사진을 올리면, 로딩 속도를 최적화하는 모든 무거운 짐이 오롯이 개발자의 어깨에 얹히게 됩니다. 브라우저 해상도별로 크기가 다른 이미지를 srcset으로 일일이 쪼개서 매핑해야 하고, 아이폰과 크롬 브라우저 사용자 각각에 맞춰 용량이 작은 WebP나 AVIF 최신 포맷으로 이미지를 미리 변환해 두어야 하며, 스크롤을 내리기 전까지 로딩을 미루는 지연 로드(lazy loading) 스크립트도 직접 구현해야 하죠. 이 노가다성 성능 작업을 완벽히 자동화해 주는 것이 바로 next/image 패키지의 <Image> 컴포넌트입니다. Next.js는 이미지 파일 하나만 슥 던져줘도 서버 단에서 실시간으로 요청 브라우저의 Accept 헤더를 파싱하여 해당 디바이스가 지원하는 가장 압축률이 높은 최신 WebP/AVIF 규격으로 알아서 변환해서 뱉어줍니다. 게다가 뷰포트 바깥의 이미지는 기본적으로 지연 로드가 들어가므로 첫 진입 시점의 네트워크 로딩 부하를 정말 마법처럼 경감해 줍니다.
Next.js Image 컴포넌트로 레이아웃 시프트(CLS) 방지하기
구글 라이트하우스(Lighthouse) 성능 점수를 매길 때 매우 까다롭게 체크하는 수치 중 하나가 바로 누적 레이아웃 이동(CLS, Cumulative Layout Shift) 점수입니다. 일반 img 태그의 경우 이미지 파일 크기를 명시하지 않으면, 웹페이지 로드 초기에는 텍스트만 먼저 주르륵 뜨고 나중에 썸네일 이미지가 뒤늦게 다운로드되면서 주변 요소들을 아래로 툭 밀어내는 레이아웃 깨짐 현상이 일어납니다. 사용자 입장에서는 버튼을 누르려다 갑자기 화면이 꿀렁이며 엉뚱한 광고 링크를 누르게 되는 최악의 UX를 선사하게 되죠. Next.js의 Image 컴포넌트는 이를 미연에 방지하기 위해 로컬 정적 이미지 파일의 경우 빌드 시점에 가로세로 비율을 강제로 미리 추론하여 공간을 빈 캔버스로 확보해 둡니다. 따라서 용량이 아주 큰 이미지가 뒤늦게 들어오더라도 전체 글 배치가 꿀렁이지 않아 브라우저 레이아웃 연산 비용을 획기적으로 낮추고 검색 노출 지수(SEO) 등급에서도 가산점을 챙길 수 있는 효자 기술입니다.
2. 컴포넌트 세부 명세 및 사용법
Next.js Image 컴포넌트에서 width, height와 fill 속성 사용법
외부 CDN이나 API를 통해 불러오는 주소의 이미지는 가로세로 규격을 Next.js 빌더가 알 수 없기 때문에 명시적으로 width와 height 값을 주어야 빌드 에러를 피할 수 있습니다. 만약 썸네일 크기가 유동적이어서 절대값을 적어주기 힘든 비정형 레이아웃 상황이라면 fill 속성을 선언하면 됩니다. 이 속성을 부여하면 이미지가 부모 요소의 전체 면적을 100% 꽉 채우게 렌더링되는데, 이때 반드시 부모 HTML 태그에 position: relative 스타일을 정의해두어야만 이미지가 뷰포트 전체로 탈출하여 배경을 다 가리는 에러를 방지할 수 있습니다. 여기에 이미지 비율이 찌그러지는 것을 막기 위해 CSS 속성인 object-fit: cover를 엮어두고 반응형 힌트를 알려주는 sizes="100vw" 속성을 추가로 선언해 두면, 스마트폰 모바일 화면부터 데스크톱 4K 화면에 이르기까지 기기 가로폭에 꼭 맞춰 리사이징된 최적화 이미지가 기막히게 전송됩니다.
import Image from 'next/image'
import thumbnail from '@/public/images/post.jpg'
// 로컬 이미지 (크기 자동 추론)
<Image src={thumbnail} alt="포스트 썸네일" />
// 외부 URL (width, height 필수)
<Image
src="https://example.com/image.jpg"
alt="외부 이미지"
width={1200}
height={630}
/>
// fill 모드
<div style={{ position: 'relative', width: '100%', height: '300px' }}>
<Image
src="/images/hero.jpg"
alt="히어로 이미지"
fill
style={{ objectFit: 'cover' }}
sizes="100vw"
priority
/>
</div>Next.js remotePatterns를 이용한 외부 이미지 도메인 안전한 허용 설정
Next.js Image 컴포넌트에서 외부 URL 이미지를 쓰려면 next.config.ts에서 해당 도메인을 명시적으로 허용해야 합니다. 허용하지 않은 외부 도메인의 이미지를 쓰면 Invalid src prop 오류가 발생하죠. images.remotePatterns 배열에 허용할 도메인 패턴을 추가하면 됩니다. protocol, hostname, port, pathname을 조합해서 허용 범위를 지정합니다. hostname에 와일드카드 패턴을 사용하면 서브도메인까지 포함해서 허용할 수 있습니다. 구형 방식인 images.domains도 있는데, 이 방식은 패스 제한이 없어 보안이 더 취약합니다. Next.js 공식 문서에서는 remotePatterns 사용을 권장하죠. 외부 이미지 URL의 도메인을 확인하고 해당 도메인만 허용 목록에 추가하는 것이 좋습니다. 와일드카드로 모든 도메인을 허용하면 악의적인 URL로 이미지 최적화 API가 남용될 수 있습니다. 설정을 변경한 후에는 Next.js 개발 서버를 재시작해야 적용됩니다. 실제로 처음 외부 이미지를 쓸 때 이 설정을 몰라서 오류 메시지에 안내된 대로 remotePatterns를 추가하니 바로 해결됐습니다.
// next.config.ts
import type { NextConfig } from 'next'
const config: NextConfig = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'example.com',
pathname: '/images/**',
},
{
protocol: 'https',
hostname: '**.cloudinary.com',
},
],
},
}
export default config3. 실무 로딩 성능 개선 기법
이미지 최적화를 위한 priority와 placeholder 블러 효과 적용법
지연 로딩이 기본 스펙인 것은 좋은 일이지만, 사용자가 사이트에 들어오자마자 마주하는 첫 장의 히어로 썸네일이나 최상단 내비게이션 바 로고 이미지까지 지연 로딩이 걸려 있으면 오히려 첫인상이 빈칸으로 보여 엄청 투박해 보입니다. 이때는 지연 로드 필터를 수동으로 바이패스 시켜주는 priority 속성을 지정해 주어야 하죠. 이 플래그가 선언되면 Next.js는 HTML 헤더 영역에 리소스 <link rel="preload"> 태그를 최우선으로 삽입하여 렌더링 시작과 동시에 가장 먼저 네트워크 다운로드를 받습니다. 추가로 로딩 중 빈 화면을 부드러운 이미지 블러 픽셀로 채워주는 placeholder="blur" 옵션을 활용하는 것을 추천합니다. 로컬 이미지는 자동으로 로딩 스케치가 합성되며, 외부 이미지는 작은 썸네일의 Base64 코드를 blurDataURL 속성에 넘겨주어 구현할 수 있습니다. 이를 적용하면 네트워크 지연 상태에서도 화면에 회색 빈 상자가 뜨는 대신 은은한 그라데이션 컬러가 먼저 피어나서 웹 서핑 시 훨씬 감성적이고 안정적인 연출이 가능해집니다.
정적 사이트 배포 환경에서의 이미지 최적화 우회 전술
Next.js를 output: 'export' 설정으로 정적 사이트로 빌드하면 런타임에 서버가 없어서 Image 컴포넌트의 자동 이미지 최적화 기능이 동작하지 않습니다. 이 상태에서 Image 컴포넌트를 쓰면 빌드 시 경고가 나거나 이미지 최적화 없이 원본 이미지가 그대로 제공되죠. 해결 방법은 여러 가지입니다. 첫 번째는 next.config.ts에서 images.unoptimized: true로 설정해 최적화 없이 원본 이미지를 그대로 쓰는 것입니다. 이미지 최적화 혜택은 포기하지만 빌드 오류를 해결할 수 있습니다. 두 번째는 외부 이미지 최적화 CDN을 custom loader로 연결하는 방식이죠. Cloudinary나 imgix를 loader로 설정하면 정적 사이트에서도 이미지 최적화 기능을 쓸 수 있습니다. 세 번째는 배포 전에 이미지를 미리 WebP로 변환해서 저장해두는 것입니다. sharp나 imagemin 같은 도구로 빌드 전 이미지를 일괄 변환하면 정적 사이트에서도 최적화된 이미지를 제공할 수 있습니다. 블로그처럼 이미지가 많지 않은 경우라면 세 번째 방법이 외부 서비스 의존 없이 단순하게 해결되는 방법입니다.
자주 묻는 질문
외부 이미지를 사용할 때 Invalid src prop 에러가 출력되면서 빌드가 실패합니다.+
Next.js는 보안을 위해 등록되지 않은 도메인 리소스의 수집을 기본 차단합니다. next.config.ts 내의 images.remotePatterns 항목에 허용할 도메인 주소의 프로토콜과 호스트네임을 추가하고 개발 서버를 완전히 종료 후 재기동하셔야 해결됩니다.
이미지 컴포넌트에 fill을 썼는데 썸네일이 찌그러지거나 레이아웃 밖으로 넘쳐흐릅니다.+
fill 모드는 컨테이너의 100%를 Absolute로 채우는 속성입니다. 따라서 이미지를 감싸고 있는 바로 바깥의 부모 태그에 반드시 position: relative 스타일과 가로/세로 높이 제한을 지정해야 하고, 이미지 자체에는 style={{ objectFit: 'cover' }} 속성을 달아주어야 찌그러짐을 방지할 수 있습니다.
관련 글
Next.js App Router 메타데이터 완벽 가이드 — generateMetadata로 SEO 최적화하는 방법
Next.js App Router에서는 Head 컴포넌트 대신 Metadata API를 써야 합니다. layout.tsx 전역 설정부터 포스트별 generateMetadata, robots.ts와 sitemap.ts까지 가볍게 정리해 보았습니다.
Next.js 정적 사이트를 Jenkins로 자동 배포하는 방법 — Jenkinsfile로 빌드부터 배포까지
Next.js 프로젝트를 output: 'export' 설정으로 정적 빌드한 뒤, Jenkins 파이프라인을 구축해 원격 운영 서버로 자동 배포하는 정석 프로세스를 알아봅니다. Credentials를 통한 SSH 안전 연동 팁도 다룹니다.
Next.js App Router에서 Google Analytics 4 설정하는 방법 — 페이지뷰와 이벤트 추적까지
UA 종료 후 GA4로 전환한 환경에서 Next.js App Router에 Google Analytics 4를 연동하는 방법을 정리했습니다. next/script 로드, usePathname 페이지뷰 추적, 커스텀 이벤트까지 다룹니다.