How-To Guide6 min readLast updated: 2026-09-22

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.

Direct Answer

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.

Verified product capabilityRead documentation →

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

Direct Answer

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.

Direct Answer

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.