Next.js Form File Uploads Without Serverless Body Limits
Bypass 4.5MB serverless request body limits on Next.js forms with client-side presigned direct uploads. Fast file handling with zero backend setup.
How do you upload large files in Next.js on Vercel without 413 payload errors?
To upload large files in Next.js without hitting serverless request payload ceilings, presign the upload on the client and PUT bytes directly to private cloud storage. Submit text fields and file IDs to your Form2Lead endpoint for instant verification and dashboard delivery.
The Vercel 4.5 MB Serverless Payload Limit
Deploying Next.js on Vercel subjects Server Actions and API Routes to a strict 4.5 MB body limit (HTTP 413 FUNCTION_PAYLOAD_TOO_LARGE). Handling user file uploads like resumes, project blueprints, or videos through standard server actions triggers instant crashes.
Client-Side Direct Upload Component
By obtaining a presigned PUT URL directly from Form2Lead on the client, your Next.js application offloads binary transfer straight to private storage, bypassing serverless function execution and memory costs entirely.
'use client';
import { useState } from 'react';
export function ContactFileUploadForm({ formKey }: { formKey: string }) {
const [file, setFile] = useState<File | null>(null);
const [loading, setLoading] = useState(false);
async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
setLoading(true);
const form = e.currentTarget;
const fileIds: string[] = [];
if (file) {
// 1. Presign URL
const presign = await fetch(`https://form2lead.com/api/v1/f/${formKey}/presign`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ fileName: file.name, contentType: file.type, sizeBytes: file.size })
}).then(r => r.json());
// 2. Direct Cloud Upload (bypasses 4.5 MB Vercel limit)
await fetch(presign.uploadUrl, { method: 'PUT', headers: { 'Content-Type': file.type }, body: file });
fileIds.push(presign.fileId);
}
// 3. Submit form data
const data = Object.fromEntries(new FormData(form));
delete data.attachment;
await fetch(`https://form2lead.com/api/v1/f/${formKey}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ...data, _f2l_files: fileIds })
});
setLoading(false);
alert('Submitted successfully!');
}
return (
<form onSubmit={handleSubmit} className="space-y-4">
<input name="email" type="email" required placeholder="Work Email" className="border p-2" />
<input type="file" onChange={(e) => setFile(e.target.files?.[0] || null)} className="border p-2" />
<button type="submit" disabled={loading} className="bg-black text-white px-4 py-2">
{loading ? 'Uploading...' : 'Send Message'}
</button>
</form>
);
}Atomic Submission Verification
When Form2Lead receives the final submission, it verifies the file was actually uploaded, validates file size and MIME type, and records the attachment in the same transaction as the lead.
How-To Q&A
Does this approach work with Next.js App Router and Server Components?
Yes. The form upload handler runs on the client using the browser fetch API, making it 100% compatible with Next.js App Router, Turbopack, and static export mode.
Will uploading large files count against my Vercel bandwidth quota?
No. Because files are uploaded directly from the browser to Form2Lead’s private cloud storage, zero binary bytes pass through your application servers or hosting bandwidth quotas.