고민보단 실천을

Next.js Route Handler 파일 업로드: multipart/form-data 파싱과 edge/node 런타임 차이 본문

카테고리 없음

Next.js Route Handler 파일 업로드: multipart/form-data 파싱과 edge/node 런타임 차이

Just-Do-It 2026. 3. 2. 13:59

Next.js Route Handler 파일 업로드: multipart/form-data 파싱과 edge/node 런타임 차이

Route Handler에서 파일 업로드를 받으려면 multipart/form-data 파싱과 런타임 선택(edge/nodejs)이 핵심입니다. 검색으로 많이 나오는 'req.body가 비어있다', '배포에서 413' 같은 문제를 피하는 기본 패턴을 정리합니다.

Next.js Route Handler 파일 업로드: multipart/form-data 파싱과 edge/node 런타임 차이
서버가 파일을 직접 받는다면 크기 제한/타입 검증이 필수입니다.

옵션/핵심 요소(3~6개)

항목의미언제 쓰는지(실무 상황)
req.formData()multipart 파싱파일/필드를 표준 API로 추출
runtimeedge vs nodejsAWS SDK/Buffer 사용이면 nodejs가 안전
size limit요청 크기 제한DoS 방지 + 플랫폼 제한(413) 대비
Content-Type 검증허용 타입 제한이미지/문서 등 화이트리스트
저장 전략직접 저장 vs presigned대용량이면 presigned가 운영에 유리

예시 코드

import { NextResponse } from 'next/server'

export const runtime = 'nodejs'

export async function POST(req: Request) {
const form = await req.formData()
const file = form.get('file')
if (!(file instanceof File)) return NextResponse.json({ message: 'file is required' }, { status: 400 })
if (file.size > 10 * 1024 * 1024) return NextResponse.json({ message: 'file too large' }, { status: 413 })
const contentType = file.type || 'application/octet-stream'
if (!contentType.startsWith('image/')) return NextResponse.json({ message: 'only images allowed' }, { status: 415 })
const buffer = Buffer.from(await file.arrayBuffer())
// TODO: buffer 저장(S3 등)
return NextResponse.json({ ok: true, size: buffer.length })

문제 상황(정확히 1개)

상황: 로컬에서는 업로드가 되는데 배포 환경에서만 413 또는 요청이 끊긴다

원인: 플랫폼/프록시(예: Vercel, Nginx)의 body size 제한 또는 타임아웃이 기본값으로 걸려 있다

해결: 대용량이면 presigned 업로드로 전환하거나, 프록시의 body 제한을 조정하고 서버에서 size limit/에러를 명확히 한다

예방 팁: 대용량 업로드가 예상되면 처음부터 '서버는 presign만, 바디는 S3 직행' 패턴으로 설계한다

참고/출처

Comments