Next.js Image hostname is not configured 에러 원인과 해결법

Next.js Image hostname is not configured 에러 원인과 해결 가이드

3초 요약: 이렇게 고치세요
  • 원인: next/image로 외부 호스트의 이미지를 불러올 때 그 호스트를 next.config.js에 등록해두지 않아서 발생
  • 해결: next.config.jsimages.remotePatterns에 해당 호스트를 추가
  • 주의: 이미지 호스팅 호스트가 새로 생길 때마다 설정 파일을 고치고 재배포해야 함 — 사용자 업로드처럼 호스트가 자주 바뀌면 와일드카드 패턴을 고려할 것
images: {
  remotePatterns: [
    { protocol: 'https', hostname: 'cdn.example-cms.com' },
  ],
}
↓ 왜 이런 에러가 나는지 원리 보기

외부 CMS나 스토리지에서 받아온 이미지 URL을 next/image에 그대로 넣었더니 화면 대신 빨간 에러 화면이 뜬 적 있으실 겁니다. "Invalid src prop ... hostname ... is not configured under images in your next.config.js"라는 메시지인데, 이미지 URL 자체는 멀쩡한데도 나는 에러라 처음 보면 당황스럽습니다.


next/image가 외부 호스트를 화이트리스트로 관리하는 이유

일반 <img> 태그는 브라우저가 어떤 URL이든 그냥 요청해서 그리면 끝입니다. 반면 next/image는 요청이 들어올 때마다 Next.js 서버(또는 배포 플랫폼의 이미지 최적화 API)가 원본 이미지를 가져와 크기를 줄이고 포맷을 변환한 뒤 캐싱해서 내려주는 구조입니다. 이때 서버가 아무 URL이나 제한 없이 대신 가져오게 허용하면, 그 최적화 엔드포인트가 임의의 외부 서버에 요청을 대신 보내주는 통로로 악용될 수 있습니다. 그래서 Next.js는 next.config.js에 명시적으로 등록한 호스트의 이미지만 최적화 대상으로 받아들이고, 등록되지 않은 호스트는 아예 렌더링을 막아버립니다.

최근 외주로 참여한 프로젝트에서 헤드리스 CMS 이미지를 붙이는 작업을 했는데, 로컬에서 테스트할 때 쓰던 샘플 이미지는 문제없이 잘 나오길래 그대로 넘어갔습니다. 그런데 콘텐츠 담당자가 실제 운영 CMS에 이미지를 올리기 시작하자 그 페이지에서만 에러 화면이 떴습니다. 처음엔 이미지 URL 자체가 깨졌나 싶어서 그 주소를 브라우저 주소창에 직접 쳐서 열어봤는데 이미지는 멀쩡히 열렸습니다. 그제서야 콘솔에 찍힌 에러 메시지를 다시 천천히 읽어보고, 문제는 이미지가 아니라 next.config.js에 그 CMS 호스트가 등록돼 있지 않아서라는 걸 알았습니다.

헷갈리기 쉬운 지점: 일반 img 태그는 왜 이 제약이 없을까

이 제약은 next/image가 제공하는 자동 최적화 기능에만 걸리는 제약입니다. 최적화 과정 자체를 포기하고 브라우저가 원본 이미지를 그대로 가져오게 하고 싶다면 unoptimized prop을 쓰면 화이트리스트 없이도 동작합니다. 다만 이 경우 리사이징·포맷 변환 같은 next/image의 핵심 장점을 포기하는 셈입니다. (지연 로딩 자체는 unoptimized 여부와 무관하게 기본으로 유지됩니다.) 신뢰할 수 없는 출처의 이미지를 어쩔 수 없이 다뤄야 하는 특수한 상황이 아니라면 권장되지 않습니다.


실전 해결 코드: remotePatterns 등록하기

문제가 되는 코드

// next.config.js — images 설정이 비어있는 상태
/** @type {import('next').NextConfig} */
const nextConfig = {};

module.exports = nextConfig;
import Image from 'next/image';

export default function Avatar() {
  return (
    <Image
      src="https://cdn.example-cms.com/uploads/avatar.jpg"
      alt="프로필 이미지"
      width={80}
      height={80}
    />
  );
}
// 콘솔: Invalid src prop (https://cdn.example-cms.com/uploads/avatar.jpg) on
// `next/image`, hostname "cdn.example-cms.com" is not configured under
// images in your `next.config.js`

해결: remotePatterns에 호스트 등록

// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'cdn.example-cms.com',
        pathname: '/uploads/**',
      },
    ],
  },
};

module.exports = nextConfig;

자주 놓치는 함정: 설정을 고쳤는데도 에러가 그대로일 때

next.config.js는 빌드·개발 서버가 시작될 때 한 번 읽히는 설정 파일이라, 파일을 고친 뒤 개발 서버를 재시작하지 않으면 브라우저를 아무리 새로고침해도 여전히 같은 에러가 뜹니다. 분명히 remotePatterns를 제대로 추가했는데도 에러가 안 없어진다면, 오타보다 먼저 개발 서버를 껐다 켜봤는지부터 확인하는 게 순서입니다.

참고: remotePatterns 필드 구성과 구버전 domains 차이

protocol·hostname·pathname을 조합해서 허용 범위를 필요한 만큼만 좁힐 수 있습니다. 이전 버전에서 쓰던 domains: ['cdn.example-cms.com'] 배열 방식도 여전히 동작은 하지만, 호스트 전체를 통째로 허용할 뿐 경로나 프로토콜을 제한할 수 없어 공식적으로 remotePatterns로 대체된 방식입니다. 새로 설정한다면 remotePatterns를 쓰는 게 맞습니다.

서브도메인이 계속 늘어나는 구조라면 hostname에 와일드카드를 써서 한 번에 처리할 수 있습니다.

{
  protocol: 'https',
  hostname: '**.example-cms.com', // 모든 서브도메인 허용
}

세 가지 대응 방식 비교

이미지 출처와 프로젝트 상황에 따라 골라 쓸 수 있습니다.

방법 동작 방식 적합한 상황
remotePatterns 프로토콜·호스트·경로 단위로 허용 범위를 좁혀서 등록 대부분의 경우에 권장되는 기본 방식
domains (구버전) 호스트 이름만으로 전체 경로·프로토콜을 통째로 허용 기존 프로젝트에 이미 설정돼 있어 당장 바꿀 이유가 없는 경우
unoptimized 최적화 자체를 건너뛰고 원본 URL을 그대로 사용 출처가 계속 바뀌어 화이트리스트 관리가 현실적으로 어려운 경우
공식 참고 레퍼런스

images 설정 전체 옵션과 보안상의 이유는 공식 문서에서 확인할 수 있습니다.

호마다의 웹개발 팁

Next.js 이미지 최적화와 설정 관련 내용을 좀 더 자세히 다룬 글은 [호마다의 IT 개발 입문 블로그] 에서 볼 수 있습니다.

댓글

이 블로그의 인기 게시물

TypeScript: Unknown vs Any 타입 차이점과 안전한 타입 가드(Type Guard)

Next.js 하이드레이션 오류 원인과 해결법 완벽 정리

Next.js App Router에서 getServerSideProps 대체 및 데이터 페칭법