UB
UploadBird
← Back to Blog
Engineering2024-12-156 min read

Type-Safe File Uploads with TypeScript

By Alex Chen

Stop wrestling with S3

Get started with UploadBird in 5 minutes. No credit card required.

Start Free Trial

Nothing breaks trust like an upload flow that fails in production because a callback didn't expect `undefined`. TypeScript helps—until uploads stay a loose `any` zone. In this post we'll make uploads type-safe from router to React component so you ship with confidence and get better DX along the way.

Start with a contract, not an endpoint

A type-safe upload starts with a schema: what files are allowed, how big can they be, and what metadata do you expect back? Define it once, generate types for both server and client, and share it so there's no drift.

Router-first design

UploadBird uses a router pattern so endpoints are declared in code, typed, and exported. That gives you:

  • Autocompletion for endpoint names (like imageUploader instead of typo-prone strings).
  • Typed metadata: whatever you return from middleware is known on the client.
  • Compile-time checks that your callbacks handle success and error shapes.

Runtime validation paired with static types

Types catch mistakes before deploy; runtime validation keeps attackers honest. Validate MIME, size, and auth in middleware, and let TypeScript tell your client what to expect.

Example: type-safe image uploads

export const fileRouter = {
  imageUploader: f({ image: { maxFileSize: "4MB" } })
    .middleware(async ({ req }) => {
      const user = await auth(req);
      if (!user) throw new UploadThingError("Unauthorized");
      return { userId: user.id, plan: user.plan };
    })
    .onUploadComplete(async ({ metadata, file }) => {
      await db.images.create({ ...metadata, url: file.url });
      return { url: file.url, width: file.width, height: file.height };
    }),
} satisfies FileRouter;

On the client, `UploadButton` only accepts valid endpoints; `onClientUploadComplete` receives typed metadata. No more guessing at response shapes or silently swallowed errors.

DX wins that add up

  • Refactors are safer—renaming an endpoint breaks at compile time, not at 2 a.m.
  • Error handling is clearer—callbacks force you to handle failure states.
  • Docs are self-updating—the router definition is the source of truth.

Treat uploads like the rest of your API surface: typed, validated, and shared. Your future self (and your users) will thank you.

Ready to simplify your file uploads?

Get Started Free
#typescript#sdk#developer-experience

Ready to get started?

Join thousands of developers who ship file uploads in minutes, not months.

No credit card required • 30-day money-back guarantee • Cancel anytime

UploadBird | Ship file uploads in minutes, not months