미들웨어 — 요청을 가로채서 리다이렉트, 인증, i18n
미들웨어 — 요청을 가로채서 리다이렉트, 인증, i18n
로그인하지 않은 사용자가
/dashboard에 접근하면/login으로 보내고 싶습니다. 모든 페이지 컴포넌트에서 인증 체크를 하는 건 너무 번거로운데, 한 곳에서 처리할 수 없을까요?
Next.js 미들웨어는 요청이 페이지에 도달하기 전에 실행되는 함수 입니다. 요청을 가로채서 리다이렉트, 리라이트, 헤더 수정 등을 수행할 수 있습니다. 인증, i18n, A/B 테스트 같은 요청 레벨의 공통 로직 을 한 곳에서 처리합니다.
기본 사용법
프로젝트 루트(또는 src/)에 middleware.ts 파일을 만듭니다.
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
console.log('요청 경로:', request.nextUrl.pathname);
return NextResponse.next(); // 다음 단계로 진행
}
이 함수는 모든 요청 에 대해 실행됩니다. 실행 위치는 서버(또는 Edge Runtime)입니다.
matcher — 어떤 경로에서 실행할지 제한
모든 요청에 미들웨어를 실행하면 정적 파일(_next/static, 이미지 등)까지 불필요하게 처리됩니다.
matcher로 실행 대상을 제한합니다.
// middleware.ts
export function middleware(request: NextRequest) {
// ...
}
export const config = {
matcher: ['/dashboard/:path*', '/settings/:path*'],
};
이제 /dashboard와 /settings 하위 경로에서만 미들웨어가 실행됩니다.
matcher 패턴 예시:
| 패턴 | 매칭 대상 |
|---|---|
/dashboard | /dashboard만 |
/dashboard/:path* | /dashboard와 모든 하위 경로 |
/((?!api|_next).*) | api와 _next를 제외한 모든 경로 |
인증 체크 — 가장 흔한 사용 사례
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const token = request.cookies.get('auth-token')?.value;
if (!token) {
const loginUrl = new URL('/login', request.url);
loginUrl.searchParams.set('from', request.nextUrl.pathname);
return NextResponse.redirect(loginUrl);
}
return NextResponse.next();
}
export const config = {
matcher: ['/dashboard/:path*', '/settings/:path*'],
};
- 쿠키에서 인증 토큰을 확인합니다.
- 토큰이 없으면
/login으로 리다이렉트하면서 원래 경로를from파라미터로 전달합니다. - 토큰이 있으면
NextResponse.next()로 요청을 통과시킵니다.
NextResponse의 주요 메서드
| 메서드 | 동작 |
|---|---|
NextResponse.next() | 다음 단계로 진행 (미들웨어 체인 또는 페이지) |
NextResponse.redirect(url) | 지정 URL로 리다이렉트 (301/302) |
NextResponse.rewrite(url) | URL은 유지하면서 다른 페이지 내용을 표시 |
NextResponse.json(data) | JSON 응답 직접 반환 |
rewrite — URL은 그대로, 내용만 다르게
export function middleware(request: NextRequest) {
const locale = request.cookies.get('locale')?.value || 'ko';
// /about 접근 시 → 내부적으로 /ko/about 또는 /en/about 페이지를 표시
return NextResponse.rewrite(
new URL(`/${locale}${request.nextUrl.pathname}`, request.url)
);
}
사용자 브라우저의 URL은 /about으로 유지되지만, 실제로는 /ko/about 페이지가 렌더링됩니다.
i18n 구현에서 자주 사용하는 패턴입니다.
헤더와 쿠키 조작
export function middleware(request: NextRequest) {
const response = NextResponse.next();
// 응답 헤더 추가
response.headers.set('x-custom-header', 'hello');
// 쿠키 설정
response.cookies.set('visited', 'true', { maxAge: 60 * 60 * 24 });
return response;
}
미들웨어에서 요청 헤더를 읽고, 응답 헤더를 추가하고, 쿠키를 설정할 수 있습니다. CORS 헤더나 보안 헤더를 여기서 일괄 추가하는 패턴도 가능합니다.
주의할 점
미들웨어에서 무거운 작업을 하면 안 된다
미들웨어는 모든 매칭 요청마다 실행됩니다. Edge Runtime에서 동작하므로 실행 시간에 제한이 있습니다.
- DB 쿼리를 직접 실행하는 것은 피합니다
- JWT 토큰 검증 정도는 괜찮지만, 복잡한 비즈니스 로직은 Server Component나 Route Handler에서 처리합니다
- 외부 API 호출이 필요하다면 응답 시간을 반드시 고려합니다
미들웨어는 하나만 존재한다
Next.js에서 미들웨어 파일은 프로젝트에 ** 딱 하나 **만 존재합니다. app/dashboard/middleware.ts 같은 경로별 미들웨어는 지원되지 않습니다.
여러 로직이 필요하면 하나의 middleware.ts 안에서 경로를 분기합니다.
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
if (pathname.startsWith('/dashboard')) {
return handleAuth(request);
}
if (pathname.startsWith('/api')) {
return handleCors(request);
}
return NextResponse.next();
}
Node.js API를 사용할 수 없다
미들웨어는 Edge Runtime에서 실행됩니다. fs, path, child_process 같은 Node.js 전용 API를 사용할 수 없습니다.
crypto, TextEncoder 등 Web API는 사용 가능합니다.
정리
| 핵심 | 내용 |
|---|---|
| 미들웨어란 | 요청이 페이지에 도달하기 전에 실행되는 함수 |
| 위치 | 프로젝트 루트 middleware.ts (하나만) |
| matcher | 실행 대상 경로 제한 |
| 주요 용도 | 인증, 리다이렉트, i18n, 헤더 조작 |
| 제약 | Edge Runtime — Node.js API 불가, 무거운 로직 금지 |
기억할 한 줄: "모든 요청의 관문. 가볍게, 빠르게, 공통 로직만."