미들웨어 — 요청을 가로채서 리다이렉트, 인증, i18n

로그인하지 않은 사용자가 /dashboard에 접근하면 /login으로 보내고 싶습니다. 모든 페이지 컴포넌트에서 인증 체크를 하는 건 너무 번거로운데, 한 곳에서 처리할 수 없을까요?

Next.js 미들웨어는 요청이 페이지에 도달하기 전에 실행되는 함수 입니다. 요청을 가로채서 리다이렉트, 리라이트, 헤더 수정 등을 수행할 수 있습니다. 인증, i18n, A/B 테스트 같은 요청 레벨의 공통 로직 을 한 곳에서 처리합니다.


기본 사용법

프로젝트 루트(또는 src/)에 middleware.ts 파일을 만듭니다.

TSX
// 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로 실행 대상을 제한합니다.

TSX
// 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를 제외한 모든 경로

인증 체크 — 가장 흔한 사용 사례

TSX
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*'],
};
  1. 쿠키에서 인증 토큰을 확인합니다.
  2. 토큰이 없으면 /login으로 리다이렉트하면서 원래 경로를 from 파라미터로 전달합니다.
  3. 토큰이 있으면 NextResponse.next()로 요청을 통과시킵니다.

NextResponse의 주요 메서드

메서드동작
NextResponse.next()다음 단계로 진행 (미들웨어 체인 또는 페이지)
NextResponse.redirect(url)지정 URL로 리다이렉트 (301/302)
NextResponse.rewrite(url)URL은 유지하면서 다른 페이지 내용을 표시
NextResponse.json(data)JSON 응답 직접 반환

rewrite — URL은 그대로, 내용만 다르게

TSX
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 구현에서 자주 사용하는 패턴입니다.


헤더와 쿠키 조작

TSX
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 안에서 경로를 분기합니다.

TSX
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 불가, 무거운 로직 금지

기억할 한 줄: "모든 요청의 관문. 가볍게, 빠르게, 공통 로직만."

댓글 로딩 중...