What static sites can and cannot do
Static sites can render HTML, run JavaScript, and submit forms. They cannot store uploaded files on their own. GitHub Pages, Cloudflare Pages, Netlify static hosting, S3, and Vercel static output all need a receiver for the uploaded file.
You have three options: build your own serverless upload endpoint, use your host's form feature if it supports files, or use a hosted form backend that receives the file and keeps your site static.
The HTML you need
File upload forms need method="POST" and enctype="multipart/form-data". Without the enctype, the browser will not send the file body.
<form action="https://splitforms.com/api/submit" method="POST" enctype="multipart/form-data">
<input type="hidden" name="access_key" value="YOUR_ACCESS_KEY" />
<label>Name <input name="name" required /></label>
<label>Email <input name="email" type="email" required /></label>
<label>Project brief <textarea name="message"></textarea></label>
<label>Attach files
<input name="files" type="file" multiple />
</label>
<input type="checkbox" name="botcheck" style="display:none" tabindex="-1" />
<button type="submit">Upload and send</button>
</form>Good use cases for static-site uploads
- Design briefs and brand assets for agency intake.
- Resume or portfolio uploads for a job application form.
- Photos for contractor quote requests.
- PDFs for legal, accounting, or consulting intake.
- Screenshots for support and bug report forms.
- Reference images for photography, event, or catering inquiries.
If the form only needs a name, email, and message, skip file uploads. They add risk and complexity. Add files only when they improve the workflow.
Security checklist
- Limit size. Set a per-file and per-submission cap.
- Limit count. Five files is enough for most intake workflows.
- Block dangerous types. Avoid executable files and unknown archives.
- Use private storage. Do not publish uploaded files to a public bucket.
- Send links, not attachments. Keep email lightweight and safer to deliver.
- Retain briefly. Delete uploads after the business workflow no longer needs them.
Optional JavaScript enhancement
Plain HTML works. Add JavaScript only when you want inline progress, client-side size checks, or a nicer success state.
const form = document.querySelector("form");
const input = form.querySelector('input[type="file"]');
input.addEventListener("change", () => {
const maxBytes = 5 * 1024 * 1024;
for (const file of input.files) {
if (file.size > maxBytes) {
alert(file.name + " is larger than 5 MB");
input.value = "";
break;
}
}
});Client-side checks are user experience, not security. The receiving backend must still enforce every file limit.
Using splitforms for static-site uploads
splitforms supports Storage-backed file uploads on paid plans when Storage is connected. The current limit is 5 files per submission at 5 MB per file. Text-only forms work without storage setup.
Start with the docs, or adapt one of the form templates from /form-templates. For broader static-site setup, see add a contact form to a static site.
FAQ
Can a static site handle file uploads?
Yes, but not by itself. Static HTML can collect a file input and submit multipart/form-data, but a backend service still has to receive, scan, store, and notify someone about the file.
Do file uploads work with plain HTML forms?
Yes. Add enctype="multipart/form-data" to the form and use input type="file". The receiving endpoint must support multipart requests.
Should file uploads be emailed as attachments?
Usually no. Email attachments create deliverability and size problems. Store the file safely and send a secure link in the notification email instead.
How large should upload limits be?
Keep limits as small as your workflow allows. For contact and intake forms, 5 files at 5 MB each is usually enough for screenshots, PDFs, resumes, briefs, and reference images.