⚙️ Next.js 10장: `next.config.ts` — 넥스트 엔진의 계기판 조립하기

2026년 4월 30일 수정됨

📋 개요

next.config.ts의 핵심 옵션과 환경 변수, rewrites, headers 설정을 실무 관점에서 정리합니다.

📋 목차


📌 이 문서를 읽기 전에

⏱️ 예상 읽기 시간: 15분(전체) / 핵심 파트만: 8분

🗺️ 이 문서의 흐름
환경 설정 파일의 위상 → 프록시 우회(CORS 타파) → 외부 호스트 선언문 → 트래픽 라우팅

🎯 이 문서를 다 읽으면 할 수 있는 것

  • 프론트엔드 환경 구축 시 발생하는 지긋지긋한 개발망 CORS 에러를 백엔드 도움 없이 rewrites 선언 하나로 혼자 격파할 수 있다.
  • next/image 컴포넌트가 S3나 외부 CDN 사진을 그릴 때 발생하는 "Hostname is not configured" 빌드 에러를 완벽하게 방어할 수 있다.

🗺️ 이 문서의 배경 세계관: '영수네 커뮤니티'

  • 영철(새로 온 주니어): "리드 님... 백엔드 서버 호출했더니 시뻘건 CORS 에러가 떠요! 백엔드 팀원한테 보안 좀 내려달라고 애원했는데 소용이 없네요. 😭"
  • 영호(FE 리드): "영철 님... 남의 집 포트로 직접 쳐들어가니까 브라우저 보안 경찰(CORS) 이 잡는 거죠! Next.js 내장 프록시 엔진(rewrites) 을 켜면, 우리 서버가 같은 식구인 척하면서 몰래 뒷구멍으로 통신을 뚫어줄 수 있다고요!"

🤔 왜 알아야 하는가

Next.js는 단순한 리액트 렌더링 라이브러리가 아니라 "스스로 웹 서버(Node.js)를 돌리는 풀스택 프레임워크" 야.
app/ 폴더 안쪽에서 네가 짜는 코드들이 '승객'이라면, 앱 루트에 존재하는 next.config.ts 파일은 그 승객들을 나르는 '비행기 조종석의 메인 계기판' 이라고 볼 수 있지.

이 계기판을 돌릴 줄 모르고 승객석에서 코드만 짜면, 외부 이미지 차단, 보안 헤더 결락, 라우팅 꼬임, 구형 브라우저 컴파일 실패 같은 인프라 레벨의 거대한 벽에 부딪히게 돼.
가이드 10장에서 이 무서운 계기판의 핵심 버튼 3개만 완벽하게 외워둔다면 프론트엔드 리드 급의 환결 설정 능력을 갖추게 될 거야.


🏗️ 비유로 먼저 이해하기

🧒 5살에게 설명한다면? (영수네 국밥집의 식재료 수입 첩보전)

기존 통신 (영철이의 무모한 직구)
내가 이웃집 식당 창고에 가서 "고기 좀 줘!" 하고 정문으로 들어갔어.
이웃집 경비 아저씨(CORS) 가 "넌 우리 집 사람(Origin) 이 아니네? 돌아가!" 하고 쫓아냈지.

Rewrites (영호의 그림자 변장술)
우리 집 웹 서버(next.config.ts) 한테 "고기 좀 구해다 줘!" 라고 심부름을 시켜.
그러면 우리 서버가 닌자 복장을 하고 이웃집 뒷문으로 살짝 들어가서 고기를 받아와.
그리고 돌아올 땐 자기 옷으로 갈아입고 와서 나한테 "자, 우리 집에서 꺼내온 고기야" 하고 건네줘.
브라우저는 "오호, 우리 집 거니까 안전하네!" 하고 맛있게 국밥을 끓여버려.


🧩 rewrites: 우아한 프록시 은폐술 🟢

프론트엔드 서버가 대신 요청을 받아서, 백엔드 서버로 남몰래 토스해주는 마법이야.

상황: 브라우저(use client)에서 외부 B2B API 호출

// next.config.ts
import type { NextConfig } from 'next'
 
const nextConfig: NextConfig = {
  // 비동기 함수로 rewrites 선언
  async rewrites() {
    return [
      {
        // 1. 브라우저야, 너는 앞으로 통신할 때 목적지를 우리 집 "/api/v1/..." 으로 해라.
        source: '/api/v1/:path*',
 
        // 2. 그러면 Next.js 서버(나)가 낚아채서 진짜 스프링 백엔드로 몰래 토스해줄게!
        destination: 'http://192.168.0.10:8080/api/v1/:path*',
      },
    ]
  },
}
 
export default nextConfig

[효과]
영철이는 클라이언트 코드 안에서 fetch("http://192.168.0.10/...") 라는 흉물스러운 하드코딩 서버 주소를 쓸 필요가 없어졌어.
그냥 프론트 안에서 당당하게 fetch("/api/v1/users") 라고 자기 자신을 찌르면 돼. 그러면 중간에 Next.js 계기판이 가로채서 백엔드로 물건을 타오기 때문에, 브라우저의 악랄한 CORS (Cross-Origin) 에러가 태생적으로 발생할 수 없는 구조가 완벽하게 세워져.


🛡️ images: 엄격한 외부 이미지 허가증 🟡

Next.js의 강력한 보물 중 하나인 <Image src={...}> (next/image) 모듈.
이 컴포넌트는 원본 이미지를 자동으로 Webp/AVIF로 압축해주고 리사이징 해주는 무서운 연산 능력이 있어.
하지만, 악의적인 해커가 이상한 바이러스 사이트 그림판(Image)을 던지면서 우회 크롤링 및 서버 연산을 남발해 지갑을 거덜 낼까 봐, Next.js는 기본적으로 "내가 승인한 외부 도메인이 아니면 절대 이미지 압축 변환 안 해줄 거임!" 하고 에러를 뿜어.

// next.config.ts
const nextConfig: NextConfig = {
  images: {
    // 💡 과거 (Next 13 이하의 domains: ['...'] 배열 방식은 폐기 예정이니 사용 금지!)
    // 💡 현재 (Next 14+ 에서는 remotePatterns 라는 훨씬 깐깐하고 정밀한 정규식 허가증을 쓴다)
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 's3.ap-northeast-2.amazonaws.com', // 우리 회사 S3 버킷 허락!
        port: '',
        pathname: '/youngsu-bucket/**', // 버킷 내 특정 폴더 사진만 허락!
      },
      {
        protocol: 'https',
        hostname: 'avatars.githubusercontent.com', // 깃허브 오픈 프로필 허락!
      },
    ],
  },
}
 
export default nextConfig

단골 실수: next.config.ts 를 한 글자라도 수정했다면? 반드시 터미널에서 구동 중인 npm run dev 서버를 완전히 껐다가(Ctrl+C) 다시 켜야만 계기판 설정이 Next.js 빌드 엔진에 반영돼! 화면 새로고침(F5) 백날 눌러도 소용없어.


🌱 redirects & headers: 트래픽 제어탑 🔴

앱이 5년 10년 늙어가다 보면 옛날 구형 페이지 URL( /old-about)을 즐겨찾기 해놨던 사용자들이 접속해서 404를 맞고 떠나는 경우가 생겨.

1) Redirects (이삿짐 안내원)

영구적으로 이사 간 주소를 브라우저 단에서 뒤통수치며 이동시켜.

// next.config.ts
const nextConfig: NextConfig = {
  async redirects() {
    return [
      {
        source: '/old-about',
        destination: '/about-us',
        permanent: true, // 💡 true면 브라우저(캐시)와 구글 검색엔진 봇에게 "나 영영 이사 갔어 (HTTP 301)" 라고 통보한다. (SEO 등급 유지의 비밀)
      },
      {
        source: '/event/2024/:id', // 와일드카드 매핑도 가능
        destination: '/event/2025/:id',
        permanent: false, // 💡 false면 임시 수리(점검창) 목적의 HTTP 307 임시 리다이렉트를 발동한다.
      },
    ]
  },
}

2) Headers (보안 트랜스포터)

iFrame(다른 남의 사이트가 우리 사이트를 액자 훔쳐보기로 띄우는 행위) 방어, XSS 방어 등을 설정할 때 쓰여.
(보안 부서에서 가장 깐깐하게 점검하는 파일이다!)

// next.config.ts
const nextConfig: NextConfig = {
  async headers() {
    return [
      {
        // 전 구역(모든 API + Page)에 적용할 보안 갑옷
        source: '/(.*)',
        headers: [
          {
            key: 'X-Frame-Options',
            value: 'DENY', // "우리 영수네 웹사이트를 남의 집 iframe 태그 안에 절대 못 가두게 막아라!"
          },
        ],
      },
    ]
  },
}

💥 에러 해결 카탈로그

에러 메시지가 뜨면 Ctrl+F로 검색해봐.

Invalid src prop (...) on next/image, hostname "kakaocdn.net" is not configured under images in your next.config.js

원인: next/image를 썼는데, 허락받지 않은 외부 출처(카카오톡 프사 CND 등) URL 문자열이 날아왔음.
해결책: next.config.ts 안에 위 챕터에서 배운 remotePatterns 룰을 적용하고, 반드시 개발 서버 터미널 프로세스를 껐다(npm run dev 재시작) 켜야 함.

Rewrite source (...) cannot have both (...) and a path match!

원인: rewrites 작성 시 경로 정규식(Path-matching) 문법을 틀림.
해결책: /:path* (모든 하위 경로 통째 매핑) 와 /:id (딱 하나의 동적 뎁스 매핑) 의 공식 문법 기호를 숙지하고 오타를 점검할 것.


🏁 이번에 배운 내용 총정리

기능 이름역할 및 패러다임핵심 키워드
rewrites브라우저 몰래 프론트 서버가 대신 백엔드 통신 가로채기CORS 에러 물리치기, 보안 URL 은폐
images무거운 자체 최적화 서버 엔진의 외부 침입 차단망 설정remotePatterns, 허가된 S3 호스팅 그림판 방어
redirects기존 즐겨찾기 유저와 구글 크롤러 봇에게 이사실 통보permanent (영구 캐시 301 vs 임시 307), SEO 방어
headers서버가 브라우저에 내려보내는 HTTP 수준의 철옹성 방패X-Frame-Options, 보안 인증, 커스텀 태그 주입

📝 마무리 퀴즈

Q1. rewrites와 redirects의 가장 큰 차이는?

정답: rewrites는 주소창을 유지한 채 내부 목적지를 바꾸고, redirects는 브라우저를 다른 URL로 이동시킨다.

💡 상세 해설: CORS를 피하기 위한 내부 프록시에는 rewrites가 자연스럽고, URL 체계를 바꾸는 공개 이동에는 redirects가 맞다.


Q2. 외부 이미지를 허용할 때 domains보다 remotePatterns가 유리한 이유는?

정답: 프로토콜, 호스트, 경로까지 더 정밀하게 제한할 수 있기 때문이다.

💡 상세 해설: 이미지 최적화 서버가 아무 외부 URL이나 가져오게 두면 보안과 비용 문제가 생길 수 있다. 허용 범위를 좁히는 설정이 필요하다.


Q3. 영철이의 테스트 타임: /api/spring/:path*를 백엔드로 넘기고 싶지만 사용자는 같은 도메인만 보게 하고 싶다. 무엇을 쓸까?

정답: next.config의 rewrites로 source와 destination을 매핑한다.

💡 상세 해설: 브라우저 입장에서는 같은 출처로 요청하므로 CORS 부담이 줄고, 서버 설정에서는 백엔드 목적지를 숨길 수 있다. 단, 인증 헤더와 쿠키 전달 정책은 별도로 확인해야 한다.

🐣 영철이의 퇴근 일기

오늘은 next.config가 잡다한 설정 파일이 아니라 런타임 정책의 입구라는 걸 알았다.

💡 "설정은 편의를 여는 동시에 보안과 캐시 경계를 만드는 코드다."

다음 설정 변경 PR에는 왜 rewrite인지 redirect인지 근거를 꼭 적겠다.

🔗 더 알아보기


🔗 더 알아보기