개인의 기록
  • 소개
  • 프로젝트
  • 글
  • 링크

© 2026 newgirok

← 글 목록

Next.js Middleware — 요청 처리 전에 실행되는 함수

2025년 6월 2일
Next.jsMiddlewaremiddleware.tsNextResponse인증

HTTP 요청이 페이지나 API Route에 도달하기 전, Middleware가 먼저 실행된다. 인증 토큰 검증, 로케일 감지, A/B 테스트 플래그 주입 등 모든 요청에 공통으로 적용해야 하는 로직을 한 곳에서 처리할 수 있다. Next.js 12부터 Edge Runtime 위에서 동작하므로 지연 시간이 거의 없다.

middleware.ts 위치와 실행 순서

middleware.ts(또는 .js)는 프로젝트 루트 또는 src/ 디렉토리 바로 아래에 위치해야 한다. pages/나 app/ 안에 두면 인식되지 않는다.

project/
├── src/
│   ├── middleware.ts   ← 여기
│   └── app/
│       └── page.tsx
└── next.config.ts

요청 흐름은 다음과 같다.

Client Request
      │
      ▼
┌─────────────┐
│  Middleware  │  ← 모든 경로에서 먼저 실행
└──────┬──────┘
       │  NextResponse.next() / redirect() / rewrite()
       ▼
┌─────────────┐
│  App Router  │  (또는 Pages Router)
└─────────────┘

matcher로 실행 범위 제한

기본적으로 Middleware는 정적 파일(_next/static, favicon.ico 등)을 제외한 모든 경로에서 실행된다. matcher 설정으로 범위를 명시적으로 좁힌다.

// middleware.ts
export const config = {
  matcher: [
    '/dashboard/:path*',
    '/api/private/:path*',
  ],
}

matcher: 정규식 기반 경로 필터. 배열로 여러 패턴을 지정할 수 있다.

NextRequest / NextResponse

Middleware 함수는 NextRequest를 받아 NextResponse를 반환한다.

메서드설명
NextResponse.next요청을 그대로 통과
NextResponse.redirect(url)클라이언트를 다른 URL로 리다이렉트
NextResponse.rewrite(url)URL은 유지하면서 내부적으로 다른 경로를 렌더링
import { NextRequest, NextResponse } from 'next/server'

export function middleware(request: NextRequest) {
  const token = request.cookies.get('token')?.value

  if (!token) {
    return NextResponse.redirect(new URL('/login', request.url))
  }

  return NextResponse.next()
}

인증 체크 패턴

실제 프로젝트에서 가장 많이 쓰이는 패턴은 JWT 토큰 또는 세션 쿠키 존재 여부를 검사한 뒤 미인증 사용자를 로그인 페이지로 보내는 것이다.

import { NextRequest, NextResponse } from 'next/server'
import { jwtVerify } from 'jose'

const SECRET = new TextEncoder().encode(process.env.JWT_SECRET)

export async function middleware(request: NextRequest) {
  const token = request.cookies.get('session')?.value

  if (!token) {
    return NextResponse.redirect(new URL('/login', request.url))
  }

  try {
    await jwtVerify(token, SECRET)
    return NextResponse.next()
  } catch {
    return NextResponse.redirect(new URL('/login', request.url))
  }
}

export const config = {
  matcher: ['/dashboard/:path*'],
}

jose: Web Crypto API 기반의 경량 JWT 라이브러리. Edge Runtime에서 사용 가능하다. Node.js 전용인 jsonwebtoken은 Middleware에서 동작하지 않는다.

헤더 조작

NextResponse.next에 headers 옵션을 전달해 요청·응답 헤더를 추가하거나 덮어쓸 수 있다. 서버 컴포넌트로 사용자 정보를 전달할 때 유용하다.

export function middleware(request: NextRequest) {
  const requestHeaders = new Headers(request.headers)
  requestHeaders.set('x-user-id', getUserId(request))

  return NextResponse.next({
    request: { headers: requestHeaders },
  })
}

서버 컴포넌트에서는 headers 함수로 x-user-id를 읽으면 된다. Middleware에서 DB를 직접 조회하는 것은 지양하고, 가볍고 빠른 연산만 수행하는 것이 원칙이다.

← 이전 글Next.js Metadata — SEO를 위한 메타 태그 관리
다음 글 →Next.js 환경 변수 — 클라이언트와 서버 환경 변수 분리