UploadThing

UploadThing

UploadThing: The Typed Upload Layer Your Stack Needs

UploadThing: The Typed Upload Layer Your Stack Needs

Jun 18, 20266 min readBy UploadThing Blog

File uploads are the cockroach of web development. Every team thinks they've solved it. Almost none of them have. The typical S3-based DIY approach involves presigned URLs, a handrolled middleware layer, auth checks scattered across three files, and a frontend contract nobody documented. It works until it doesn't, and when it breaks, it usually breaks badly: leaked files, broken upload states, or a surprise bandwidth bill. UploadThing is a direct answer to that problem. It launched as an opinionated, TypeScript-first file upload platform that wraps storage, bandwidth, and delivery behind a typed SDK with an explicit server/client split. For teams already living in Next.js, tRPC, and Prisma, it fits the pattern: a higher-level abstraction over raw cloud primitives that trades configurability for correctness and speed. Here's why engineering leaders should pay close attention.

What UploadThing Actually Ships

The core product is an end-to-end upload workflow: from a UI button in `client.tsx` to a typed handler in `server.ts`, with UploadThing's infrastructure handling the transfer, storage, and bandwidth in between. The SDK is TypeScript-native throughout, meaning your file type constraints, size limits, and allowed MIME types are defined once in server-side code and automatically inferred on the frontend. No more copy-pasting validation logic between layers. The architecture follows a deliberate security model: "Your Auth. Our Bandwidth." Authentication and authorization logic lives on your server, under your control. UploadThing never touches your auth tokens or user sessions. It just handles the heavy lifting of moving bytes reliably. This isn't a minor implementation detail: it's a fundamental design choice that prevents an entire class of file-access vulnerabilities that plague DIY upload systems where authorization checks get bolted on after the fact. The dashboard is intentionally developer-facing: you get a structured view of uploaded files, audit logs, and retention windows rather than the raw object-storage console experience you'd navigate in S3 or GCS. For teams without dedicated infrastructure engineers, that difference in cognitive overhead is significant.

The "Better Than S3" Argument, Properly Understood

UploadThing markets itself as a "better than S3" developer experience, and that framing is accurate but needs unpacking. S3 isn't the real competition here. The honest competitive set is Uploadcare, Filestack, Upload.io, and Cloudinary's Upload API: platforms that similarly abstract away raw storage but have historically been built around image/video transformation workflows or widget-first integrations that don't compose cleanly with modern TypeScript backends. These tools are powerful if you need media processing pipelines. They're overkill and often awkward if you just need reliable, typed file uploads with clean server-side auth. UploadThing's bet is tighter: it's not trying to be a media platform. It's trying to be the upload layer for TypeScript applications in the same way Prisma is the database layer. Opinionated, typed, fast to adopt, and designed around the workflow you're already using. That's a more defensible position than "cheaper S3 with a UI." It's an ergonomics argument for a specific audience.

Where This Fits in Your Stack

The entry-level plan includes approximately 2 GB of storage and 7 days of audit log retention, which is sufficient for prototyping and early-stage products. Critically, UploadThing advertises flat, calculator-free pricing rather than the metered-by-request or tiered-bandwidth models that make object storage costs unpredictable at scale. For engineering leaders managing cloud budgets, that distinction matters: unpredictable egress fees are a known pain point with raw S3 setups, especially when upload volume spikes. The practical adoption profile looks like this:

Team ProfileUploadThing Fit
Next.js / TypeScript app with server-side authStrong
React SPA with a separate API backendStrong
Image/video processing pipeline neededPartial
Multi-cloud portability is a hard requirementEvaluate carefully
Existing S3 infra with dedicated DevOps teamLower urgency

For a TypeScript-first team shipping a product with user file uploads, the time-to-correct-implementation delta is the core value proposition. Getting presigned URL flows right, handling upload failures gracefully, and keeping auth logic server-side are all things developers get wrong repeatedly. UploadThing encodes those patterns by default.

The Strategic Angle Most Coverage Misses

Here's the take you won't find in most writeups: the real question isn't "is this better than S3?" The real question is: who owns the upload contract between your frontend and backend teams? In a DIY S3 setup, that contract is implicit. It lives in scattered middleware, undocumented presigned URL TTLs, and frontend assumptions about response shapes. It's owned by whoever wrote it and maintained by whoever happens to be looking at the code. That's a fragile dependency. When you introduce a typed upload layer like UploadThing, the contract becomes explicit and enforced. The server-side router defines what file types, sizes, and auth conditions are acceptable. The TypeScript SDK generates a typed client that reflects those constraints automatically. Frontend engineers know exactly what they can upload and when. Backend engineers know exactly what the server will receive. This is the same thesis that made tRPC compelling: replace informal API contracts with generated, enforced types. Applied to file uploads, it means fewer integration bugs, faster onboarding for new engineers, and a cleaner handoff surface between teams. For startups scaling from 3 to 15 engineers, that kind of contract clarity compounds over time.

The deeper lock-in concern: adopting any managed upload layer means the shape of your upload workflow depends on a third-party API. That's a real trade-off. But it's the same trade-off you made with your ORM, your auth provider, and your email service. The question is whether the DX and correctness gains justify the dependency. For most TypeScript product teams, the answer is yes, as long as the vendor is focused on the right abstraction layer (upload infrastructure, not media processing), and UploadThing is precisely focused there.

Concrete Recommendations

If you're starting a new Next.js or TypeScript project with file upload requirements: Adopt UploadThing as your default upload layer. The free tier gives you enough runway to validate the integration before committing, and the TypeScript ergonomics will save meaningful engineering time during development. If you're maintaining a DIY S3 upload flow: Audit your current implementation against three questions:

Is your authorization logic server-side and consistently enforced, or is it partially handled on the frontend?

Do your frontend engineers have a typed contract for what they can upload, or are they working from informal documentation?

Have you had any upload-related security incidents or unexpected storage/bandwidth costs in the past year?

If any answer is uncomfortable, UploadThing is worth a proof-of-concept sprint. The migration surface is bounded: uploads are typically isolated enough in a codebase that replacing the upload layer doesn't require a broader refactor. If you're evaluating Uploadcare, Filestack, or Cloudinary for a new project: Be explicit about whether you need media processing (transformation, delivery optimization, CDN) or just reliable upload infrastructure. If it's the latter, a platform built around TypeScript-first upload infrastructure is a cleaner fit than a media platform you'll use at 20% of its capability. If multi-cloud portability is a hard requirement: UploadThing isn't the answer today. Build on raw object storage with a well-abstracted internal layer. But be honest with yourself about whether that requirement is real or theoretical: most startups that say they need multi-cloud portability never actually exercise it.

The Larger Pattern

UploadThing is part of a broader movement in developer tooling: the TypeScript ecosystem is generating a new layer of infrastructure abstractions that are opinionated, fast to adopt, and composable with each other. Prisma for databases, Clerk for auth, Resend for email, and now UploadThing for file uploads. Each one makes the same bet: that developers would rather configure well-designed defaults than engineer primitive operations from scratch. This matters for engineering leaders because it changes the calculus on in-house infrastructure expertise. If your upload layer is a managed, typed API, your frontend engineers can wire it up correctly without deep knowledge of S3 IAM policies or multipart upload edge cases. That's not dumbing down infrastructure: it's allocating specialized knowledge to the right layer. The teams most at risk are those that reject these abstractions on principle (usually citing "control" or "cost") while quietly accepting the hidden cost of repeated implementation bugs, slow onboarding, and security incidents in subsystems that aren't core to their product. File uploads are not a competitive advantage for a SaaS company. Correct, secure, maintainable file uploads are table stakes. UploadThing is built on the premise that you should spend your engineering time on what differentiates your product, not on getting presigned URLs right. For TypeScript teams shipping in 2026, that premise is hard to argue with.

Get started with UploadThing

Want to start building with UploadThing? Here's a quickstart:

bash
1export const fileRouter = {
2  imageUploader: f({ image: { maxFileSize: "4MB" } })
3    .middleware(async ({ req }) => {
4      // This code runs on your server before upload
5      const user = await auth(req);
6
7      // Throw to block uploading
8      if (!user)
9        throw new UploadThingError("Unauthorized");
10
11      // Return metadata to client
12      return { userId: user.id };
13    })
14    .onUploadComplete(async ({ metadata, file }) => {
15      // ...
16    }),
17} satisfies FileRouter;

Want frictionless uploads for your app?

Join top developers using UploadThing’s API to secure uploads, automate storage, and focus on building great features.

UploadThingUploadThing

Practical file upload tips for developer teams.

© 2026 Ping Labs. All rights reserved.