TechFeedTechFeed
Backend

413, body size, 서버 액션 | 업로드만 본문 한도에 걸리면?

업로드만 413이면 파일이 깨진 게 아니라 서버 액션 기본 1MB 또는 버셀 함수 4.5MB 본문 한도를 넘긴 줄입니다. bodySizeLimit으로 올리는 한도와 플랫폼 한도를 나누고, 더 큰 파일은 함수 밖으로 보냅니다. Next.js, Vercel, nginx, 한국 1인 개발자 기준. 2026년 9월 serverActions와 Functions 한도 문서.

by

업로드만 413이 뜨면 파일이 깨진 게 아니라, 요청 본문이 서버 액션 기본 1MB나 버셀 함수 4.5MB 한도를 넘긴 줄입니다. 로컬에서 작은 폼은 되고 휴대폰 사진만 막히는 패턴이 흔합니다.

한도를 설정으로 올리는 곳과, 플랫폼이 그 위에서 다시 자르는 곳을 나눠 봐야 합니다. 액션 한도를 3MB로 올려도 버셀에 배포하면 4.5MB에서 다시 막힐 수 있어, 숫자 두 개를 같이 보세요.

폼 필드와 파일 용량을 네트워크 탭에서 먼저 확인하고, 큰 파일은 함수를 통과하지 않게 저장소로 바로 올리는 방법이 있습니다. 근거는 Next.js serverActions 문서Vercel Functions 한도에 있습니다.


413 문장으로 한도부터 가리기

응답 본문의 단어가 어느 한도인지 알려 줍니다.


같은 413이라도 자른 주체가 다릅니다. 넥스트 서버 액션은 요청 본문 기본 한도가 1MB입니다. 2026년 9월 serverActions 문서는 큰 본문 파싱이 서버 자원을 잡아먹는 것을 막기 위한 기본값이라고 적고, experimental.serverActions.bodySizeLimit으로 바꿉니다. 문자열 '2mb''500kb'처럼 bytes가 읽는 형식을 넣습니다.


버셀에 올린 함수는 그 위에서 한 번 더 잘립니다. Vercel Functions 한도 문서는 요청 본문과 응답 본문의 최대를 4.5MB로 적고, 넘으면 413: FUNCTION_PAYLOAD_TOO_LARGE를 돌려준다고 합니다. 넥스트 설정을 10MB로 올려도 이 플랫폼 한도는 그대로입니다. 로컬 next dev에서 2MB 액션이 1MB 때문에 막히고, 한도를 3MB로 올린 뒤 배포하면 4.5MB 사진에서 다시 막히는 순서가 흔합니다.


연결이 중간에 끊긴 ECONNRESET과는 상태 코드가 다릅니다. 리셋은 응답이 오기 전에 소켓이 닫힌 줄이고, 413은 본문 크기를 보고 거절한 줄입니다. 리셋 쪽은 ECONNRESET 글을 보면 됩니다.


서버 액션 1MB와 버셀 함수 4.5MB와 nginx 1MB가 요청을 차례로 자르는 그림
같은 413이라도 액션 한도, 플랫폼 한도, 프록시 한도 중 어디서 잘렸는지가 다르다. 자체 인포그래픽

본문을 자르는 세 관문

액션, 버셀 함수, 앞단 프록시를 순서대로 봅니다.


첫 관문은 서버 액션입니다. 한도는 원시 HTTP 본문 전체에 적용됩니다. multipart 경계와 파트 헤더가 더해지므로, 문서가 말하는 여유는 보통 10KB에서 20KB입니다. 파일이 한도와 거의 같으면 파일만 재면 통과할 것 같아도 거절됩니다. 두 번째 관문은 버셀 4.5MB입니다. 응답이 너무 커도 같은 계열의 한도에 걸리고, 그때는 요청이 아니라 돌려주는 JSON이 큰 경우입니다. 세 번째 관문은 직접 띄운 nginx입니다. client_max_body_size 기본값은 1m이라, 노드 로그가 비어 있는데 브라우저만 413 HTML이면 프록시가 먼저 자른 것입니다.


어디 한도인가기본 숫자보이는 말
서버 액션1MBbody size limit, serverActions 문서 주소
버셀 함수4.5MBFUNCTION_PAYLOAD_TOO_LARGE
Pages API bodyParser1mbpages/api의 config sizeLimit
nginx1m앱 로그 없이 413 HTML

Pages 라우터의 pages/apiexport const configbodyParser.sizeLimit 기본이 1mb입니다. 앱 라우터 Route Handler는 그 config를 쓰지 않고 요청 스트림을 직접 읽지만, 버셀에 올리면 4.5MB 플랫폼 한도는 그대로 적용됩니다. 앱 라우터로 옮겼다고 업로드 한도가 사라지지는 않습니다.


서버 액션 본문 한도를 2MB로
/** @type {import('next').NextConfig} */ module.exports = { experimental: { serverActions: { bodySizeLimit: '2mb', }, }, }

한도를 올릴지 경로를 뺄지

4.5MB 아래의 폼만 설정으로 올립니다.


프로필 이미지처럼 1MB를 조금 넘는 파일은 bodySizeLimit'2mb'로 올리면 액션이 통과합니다. 여유 10KB에서 20KB를 빼고 고르세요. 3MB짜리 휴대폰 원본은 버셀에서 함수를 통과시키는 한 4.5MB 안에 들 수 있지만, 원본이 5MB를 넘으면 설정을 더 올려도 FUNCTION_PAYLOAD_TOO_LARGE가 납니다. 그 경우는 한도를 푸는 것이 아니라 파일이 함수 본문에 실리지 않게 해야 합니다.


버셀 지식 문서는 큰 업로드를 함수에 넣지 말고 저장소로 브라우저가 직접 올리라고 안내합니다. 서버는 짧은 토큰만 주고, 파일 바이트는 Blob 같은 저장소로 바로 갑니다. 그러면 4.5MB 함수 한도를 우회합니다. 자체 서버에 nginx만 있다면 client_max_body_size를 액션 한도보다 작지 않게 맞춥니다. 프록시가 1m인데 액션만 10mb이면 요청은 노드에 도착하기 전에 잘립니다.


  • [ ] 네트워크 탭에서 상태 413과 응답 문장을 봤다
  • [ ] 파일 크기와 multipart 여유를 더했다
  • [ ] 1MB 근처면 bodySizeLimit을 문서 형식으로 올렸다
  • [ ] 4.5MB를 넘으면 함수를 통과시키지 않는 업로드로 바꿨다
  • [ ] nginx를 쓰면 client_max_body_size를 같이 봤다

작은 파일은 bodySizeLimit을 올리고 큰 파일은 저장소로 직접 올리는 분기 그림
4.5MB를 넘는 파일은 함수 본문에 실리지 않게 브라우저에서 저장소로 보낸다. 자체 인포그래픽

로컬은 되고 프리뷰만 413일 때

프리뷰만 실패하면 플랫폼 4.5MB를 먼저 의심합니다.


로컬에서 3MB가 통과했다는 것은 액션 한도를 이미 그 위로 올렸다는 뜻에 가깝습니다. 같은 파일을 프리뷰에 올리자 FUNCTION_PAYLOAD_TOO_LARGE가 보이면 넥스트 설정은 더 올려도 소용이 없습니다. 버셀 한도 문서의 숫자는 요청과 응답 둘 다입니다. 업로드가 작은데 413이면, 함수가 돌려주는 JSON이 4.5MB를 넘었는지도 보세요. 목록 전체를 한 번에 내려 주는 핸들러가 이쪽입니다.


응답이 HTML 오류 페이지라 클라이언트의 JSON.parse<에서 멈추면, 크기 거절이 파서 오류로 보이기도 합니다. 파서만 고치면 다시 413입니다. 그 순서는 JSON.parse 글과 같이 보면 됩니다. 브라우저가 다른 출처의 업로드 주소로 못 가면 413 대신 CORS가 나므로, 출처가 막힌 줄은 CORS 글에서 헤더를 확인하면 됩니다.


휴대폰 사진이 유독 걸리는 이유

최근 폰 원본은 한 장이 3MB에서 8MB인 경우가 많습니다.


폼 테스트에 쓰던 100KB 샘플은 1MB 액션 한도를 통과합니다. 같은 폼에 카메라 원본을 넣으면 로컬에서 먼저 1MB에 걸리고, 한도를 올린 뒤 버셀에서 4.5MB에 걸립니다. 국내 통신사 망이나 카카오에서 줄인 사진과는 별개로, 제한은 서버가 받은 바이트 수입니다. 네트워크 탭의 Request Payload 또는 Content-Length가 한도보다 큰지 보면 감으로 재지 않아도 됩니다.


액션 한도를 아주 크게 올리는 것은 문서가 막으려는 자원 소모를 다시 여는 일입니다. 통과해야 하는 최대 파일에 20KB 정도만 더해 적고, 그 위를 넘는 파일은 리사이즈하거나 직접 업로드로 빼세요. 웹훅 JSON처럼 수십 KB인 카카오, 토스 알림은 이 한도와 거의 상관이 없습니다. 파일 필드가 있는 폼만 먼저 보면 됩니다.


숫자 두 개 | 서버 액션 기본은 1MB, 버셀 함수 요청과 응답은 4.5MB입니다. 넥스트 설정은 첫 숫자만 바꿉니다. 두 번째 숫자는 파일을 함수 밖으로 보내야 넘어갑니다.


샘플 100KB는 통과하고 휴대폰 원본 사진만 1MB와 4.5MB에서 막히는 비교 그림
테스트 샘플과 폰 원본의 용량 차이가 413을 가른다. 자체 인포그래픽

참고 자료

본문 한도를 적은 공식 문서만 여기 모아 둡니다.



내부 연계: 연결 리셋, JSON 대신 HTML, CORS 프리플라이트, 쿠키와 정적 생성


인용한 한도 숫자는 2026년 9월 22일 공개 문서 기준입니다.


자주 묻는 질문

용량 한도에서 자주 나오는 질문만 답을 적습니다.


서버 액션 기본 한도는 얼마인가요?

2026년 9월 Next.js 문서 기준 1MB입니다. experimental.serverActions.bodySizeLimit에 2mb처럼 적으면 바뀝니다. multipart 경계가 10KB에서 20KB 더해지므로 파일 크기만으로 딱 맞추지 않는 편이 안전합니다.


한도를 10MB로 올렸는데 버셀에서 또 413입니다.

버셀 함수의 요청 본문과 응답 본문 한도는 4.5MB입니다. 응답 코드에 FUNCTION_PAYLOAD_TOO_LARGE가 있으면 플랫폼 한도입니다. 넥스트 숫자를 더 올려도 넘어가지 않으니, 파일을 함수 밖으로 직접 업로드해야 합니다.


로컬에서는 같은 파일이 됩니다.

로컬에는 버셀 4.5MB 제한이 없습니다. 액션 한도만 통과하면 next dev는 받습니다. 프리뷰만 실패하면 파일 크기와 응답 JSON 크기가 4.5MB를 넘는지 보세요.


nginx를 쓰면 어디를 보나요?

client_max_body_size 기본값은 1m입니다. 앱 로그에 요청이 안 남고 413 HTML만 오면 프록시가 먼저 자른 것입니다. 이 값을 액션 한도보다 작게 두지 않으면 됩니다.


JSON.parse가 꺾쇠에서 멈춥니다.

413 HTML을 JSON으로 읽어서 나는 줄인 경우가 있습니다. 네트워크 탭의 상태 코드가 413이면 파서가 아니라 본문 한도입니다. 상태 코드를 먼저 확인하고 한도를 고치면 파서 오류도 같이 사라집니다.


웹훅 JSON도 이 한도에 걸리나요?

수십 KB인 알림 본문은 1MB에 닿지 않습니다. 파일 필드가 있는 폼, 특히 휴대폰 원본 사진부터 용량을 보세요. 웹훅이 끊기면 크기보다 응답을 늦게 줘 상대가 연결을 끊었는지가 먼저입니다.


업로드 413은 액션 1MB인지 버셀 4.5MB인지부터 나누면 됩니다. 그 사이의 파일은 bodySizeLimit을 올리고, 4.5MB를 넘으면 함수 본문 밖으로 파일을 보내면 됩니다. 관련 글: 연결 리셋, HTML을 JSON으로 읽은 경우, CORS.


413body size서버 액션bodySizeLimit버셀업로드넥스트nginx백엔드개발자

함께 보면 좋은 문제 해결

EXPLORE / Backend

이어서 읽어보기

전체 토픽 둘러보기