← 전체 글로 돌아가기

Next.js

Next.js middleware를 쓰기 전에 알아야 할 것들

Next.js middleware는 Edge Runtime에서 돌기 때문에 Node.js API를 쓸 수 없고, 잘못 쓰면 모든 요청에 불필요한 처리를 붙이게 된다.

Next.js의 middleware.ts는 요청이 라우트 핸들러나 페이지에 닿기 전에 실행되는 코드다. 인증 체크, 리다이렉트, 헤더 주입 같은 작업을 한 곳에서 처리할 수 있어서 편해 보이지만, 쓰기 전에 파악해야 할 제약이 꽤 있다.

Edge Runtime에서 돈다는 뜻

middleware는 Node.js 런타임이 아니라 Edge Runtime에서 실행된다. Vercel 기준으로는 CDN 엣지 노드에서 돌고, 자체 서버라면 독립 워커처럼 동작한다. 이 때문에 Node.js 기본 모듈을 쓸 수 없다.

// 이런 import는 middleware.ts에서 동작하지 않는다
import fs from 'fs';
import { createHash } from 'crypto'; // Node.js 내장 crypto — Edge 불가

// Web Crypto API는 가능
const hash = await crypto.subtle.digest('SHA-256', data);

Prisma, Mongoose 같은 DB 클라이언트도 쓸 수 없다. 인증 미들웨어를 짤 때 DB 조회가 필요하다면, JWT나 세션 토큰처럼 외부 요청 없이 검증 가능한 방식을 써야 한다.

matcher 설정이 없으면 모든 요청에 실행된다

middleware.ts 파일이 프로젝트 루트에 있으면 기본적으로 모든 경로에 대해 실행된다. 정적 파일 요청(_next/static, favicon.ico)까지 포함해서다. matcher로 범위를 좁혀야 한다.

// middleware.ts
export const config = {
  matcher: [
    // _next 정적 파일, 이미지, api를 제외한 경로에만 실행
    '/((?!_next/static|_next/image|favicon.ico|api/).*)',
  ],
};

범위를 좁히지 않으면 정적 파일을 서빙할 때도 미들웨어 로직이 실행돼서 불필요한 지연이 생긴다.

언제 middleware를 쓰고 언제 안 쓰나

middleware가 적합한 경우는 다음과 같다.

  • 쿠키나 JWT를 읽어서 로그인 여부만 판단하는 인증 게이트
  • A/B 테스트용 쿠키 세팅
  • 특정 경로를 다른 URL로 리다이렉트
  • 요청 헤더에 공통 값 추가 (예: 요청 ID)

반대로 피해야 할 경우다.

  • DB 조회가 필요한 권한 체크 → API route handler나 서버 컴포넌트에서 처리
  • 무거운 연산 — Edge 환경은 CPU 시간이 제한돼 있다
  • 세션 데이터를 읽어 복잡한 분기를 처리 — middleware가 비대해진다

Response를 반환하면 이후 처리는 실행되지 않는다

import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

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

  if (!token) {
    // 여기서 응답을 반환하면 라우트 핸들러까지 가지 않는다
    return NextResponse.redirect(new URL('/login', request.url));
  }

  // 통과시킬 때는 next()를 반환
  return NextResponse.next();
}

간단히 쓰면 편리한 도구지만, 범위와 런타임 제약을 모르면 예상과 다르게 동작한다.