The full React component
Drop this into any Vite or CRA app. It uploads on file-select and shows the resulting URL.
import { useState } from 'react';
export default function FileUploader() {
const [url, setUrl] = useState(null);
const [loading, setLoading] = useState(false);
async function onChange(e) {
const file = e.target.files?.[0];
if (!file) return;
setLoading(true);
const fd = new FormData();
fd.append('file', file);
const r = await fetch('https://filepost.dev/v1/upload', {
method: 'POST',
headers: { 'X-API-Key': import.meta.env.VITE_FILEPOST_KEY },
body: fd,
});
const data = await r.json();
setUrl(data.url);
setLoading(false);
}
return (
<div>
<input type="file" onChange={onChange} disabled={loading} />
{url && <a href={url}>{url}</a>}
</div>
);
}
That's the whole upload flow. 27 lines including the JSX. No backend, no IAM, no CDN distribution to wait three days to provision.
FilePost vs S3 + presigned URLs vs uploadthing — for React specifically
| What you do | FilePost | S3 + presigned URL | uploadthing |
|---|---|---|---|
| Lines of React code | ~12 | ~40 (plus a Lambda for signing) | ~30 (provider + hook) |
| Backend required | No | Yes (signing endpoint) | Yes (Next.js API route) |
| Permanent URL | Yes | No (object key, not URL) | Yes |
| CORS config needed | No | Yes (bucket policy) | No |
| Time-to-first-upload | ~20 min | 2–4 hours | ~30 min (Next.js only) |
| Free tier | 300 / mo, no card | 5 GB / 20k requests, no card | 2 GB total, no card |
| Paid plan starts | $9 / mo | ~$0.023 / GB stored | $10 / mo |
| Framework lock-in | None — works anywhere | None | Strong (Next.js / React Server Components) |
The opinion
If you're shipping a Vercel-hosted Next.js app and want the most opinionated DX possible, uploadthing is fine. If you're shipping anything else — Vite, CRA, Remix, React Native bridge, a one-off internal tool — FilePost is roughly half the moving parts and a third of the price.
S3 directly is the right answer at scale (10+ TB/month). For everything below that, you're paying with your time. The S3 + CloudFront stack is roughly six configuration steps that all need to be right before a single byte uploads. FilePost is one POST.
Where this came from
FilePost exists because the same problem kept showing up: "I need to upload a file from React and get a URL." Every React side project, every internal tool, every dashboard widget. Setting up S3 from scratch took an afternoon every time, and the answer never changed.
One weekend later it was a FastAPI server, a Backblaze B2 bucket, and a Cloudflare CDN. The React surface is exactly what you see above — no clever wrapper, no React-specific binding, just the same multipart endpoint everyone else uses.
When NOT to use FilePost from React
- You need server-side image transforms (resize, crop, watermark, smart-crop). Cloudinary or Uploadcare do that better — bundled into their upload pipeline.
- You need OCR or AI tagging on every uploaded file. Filestack has that built in.
- The user is uploading one file once, then leaving. Use
transfer.shor0x0.st— no signup needed. - You're already pushing 10+ TB/month of egress. You've graduated; raw S3 + CloudFront becomes cheaper at that scale.
Going further
This page is the decision. The deep-dive is the blog post — drag-and-drop with react-dropzone, progress indicators, custom hooks, Next.js App Router API routes, TypeScript types, error-handling patterns, and the production checklist.