⚙️ Next.js 10장: `next.config.ts` — 넥스트 엔진의 계기판 조립하기
📋 개요
next.config.ts의 핵심 옵션과 환경 변수, rewrites, headers 설정을 실무 관점에서 정리합니다.
📋 목차
- 📌 이 문서를 읽기 전에
- 🤔 왜 알아야 하는가
- 🏗️ 비유로 먼저 이해하기
- 🧩
rewrites: 우아한 프록시 은폐술 🟢 - 🛡️
images: 엄격한 외부 이미지 허가증 🟡 - 🌱
redirects&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인지 근거를 꼭 적겠다.