js

Robust File Uploads in Next.js with UploadThing and Prisma

Learn secure, scalable file uploads in Next.js using UploadThing and Prisma, with auth, large file support, and database syncing.

Robust File Uploads in Next.js with UploadThing and Prisma

I’ve been building web applications for a while now, and one task consistently proves more complex than it first appears: file uploads. It starts simply enough—a form, an input, a bit of server logic. But as an application grows, so do the requirements. What about large files? Security? Organizing everything in a database? Suddenly, that simple feature feels like a house of cards, ready to topple in production. I wanted to find a better way, a method that is robust, scalable, and fits neatly into the modern TypeScript ecosystem of Next.js. That search led me to combine UploadThing for handling the files and Prisma for managing the data. Let me show you what I built.

So, why is uploading files so tricky? We’ve all used an <input type="file">. It works, right? But what happens when a user tries to upload a massive video? Your server might freeze trying to process it all at once. How do you stop someone from uploading an executable file disguised as an image? And where do you even store these files so they’re reliable and fast to access worldwide? These aren’t edge cases; they’re standard production concerns a basic solution ignores.

This is where a service like UploadThing changes the game. Instead of sending the file to your Next.js server, your server acts as a manager. It authenticates the user and provides a secure, temporary permission slip for the browser. The browser then uses that slip to upload the file directly to UploadThing’s storage. Your server never has to handle the heavy file data. It only gets a neat report afterward with the file’s URL, size, and type. This keeps your application fast and lean.

How do we keep track of all these uploaded files? This is where Prisma shines. While UploadThing manages the physical file, we need to store information about it in our database. Think of it like a library: the books are stored in the building (UploadThing), but the catalog cards (Prisma) tell us the title, author, and location. We can link files to specific users, projects, or posts. This connection is crucial for building real features.

Let’s look at how you set this up. First, you define your “upload router” in a server-side file. This is where you set the rules. You can specify that a route for profile pictures only accepts images under 4 megabytes. Another route for document uploads might accept PDFs and Word files. You also add your authentication check here. If a user isn’t logged in, the upload request stops before it even starts.

Here’s a glimpse of what that router setup looks like:

// app/api/uploadthing/core.ts
import { createUploadthing } from "uploadthing/next";

const f = createUploadthing();

export const ourFileRouter = {
  profileImage: f({ image: { maxFileSize: "4MB" } })
    .middleware(async ({ req }) => {
      const session = await getAuthSession();
      if (!session) throw new Error("Unauthorized");
      return { userId: session.user.id };
    })
    .onUploadComplete(async ({ metadata, file }) => {
      console.log("Upload completed for user:", metadata.userId);
      console.log("File URL:", file.url);
      // Here, you can save file.url and metadata to your database using Prisma
    }),
};

Did you notice the onUploadComplete function? This is your golden ticket. Once UploadThing confirms the file is safely stored, it calls this function. Inside it, you have all the information you need—the secure URL, the file size, the user who uploaded it. This is the perfect moment to create a record in your database with Prisma.

For example, after a user uploads an avatar, you can immediately update their profile in the database:

// Inside onUploadComplete
await prisma.user.update({
  where: { id: metadata.userId },
  data: { image: file.url },
});

Now, what about security? You can’t just leave every uploaded file with a public URL. Some files should be private. UploadThing helps here too with signed URLs. You can generate a special URL that only works for a short time to view or download a protected file. This means you can store invoices or private documents with confidence, controlling exactly when and how they are accessed.

Here is a simple way to create a signed URL for a file:

// app/api/file/[key]/route.ts
import { getSignedUrl } from "@uploadthing/next-legacy";

export async function GET(
  request: Request,
  { params }: { params: { key: string } }
) {
  const url = await getSignedUrl(params.key, { expiresIn: 3600 }); // Expires in 1 hour
  return Response.json({ url });
}

Handling large files is another common worry. What if your user needs to upload a 2-gigabyte design file? The traditional method would fail. UploadThing handles this automatically by breaking the large file into smaller pieces, or “chunks,” and uploading them separately. If the internet connection drops, it can resume from where it left off. This process is invisible to you as the developer and a much better experience for your user.

Building the user interface is straightforward with the provided React components. You get a clean, functional upload area with drag-and-drop support, progress indicators, and a list of uploaded files. It looks professional and works reliably without you writing a lot of UI code.

// components/avatar-uploader.tsx
import { UploadButton } from "@uploadthing/react";

export function AvatarUploader() {
  return (
    <UploadButton
      endpoint="profileImage"
      onClientUploadComplete={(files) => {
        alert("Upload Completed!");
      }}
    />
  );
}

After everything is built, how can you be sure it works? Testing is key. You can write tests that simulate the upload process without actually hitting external services. Libraries like MSW (Mock Service Worker) can intercept the API calls your component makes, allowing you to test the entire user flow—from clicking the button to seeing a success message—quickly and reliably.

Why go through this effort? Because the foundation of your features matters. A wobbly, insecure upload system can create problems for years. Using tools like UploadThing and Prisma together builds a strong, type-safe foundation. You get clear rules, automatic handling of difficult problems, and a database that knows exactly what was uploaded and why. It turns a potential weak spot into one of the most reliable parts of your application.

What will you build with a system like this in place? A portfolio site for creators? A secure document portal for a business? The possibilities open up when the basic mechanics are solved. I hope this walkthrough gives you the confidence to implement solid file uploads in your own Next.js projects. If you found this helpful, please share it with other developers who might be facing the same challenges. I’d love to hear about your experiences or answer any questions in the comments below


As a best-selling author, I invite you to explore my books on Amazon. Don’t forget to follow me on Medium and show your support. Thank you! Your support means the world!


101 Books

101 Books is an AI-driven publishing company co-founded by author Aarav Joshi. By leveraging advanced AI technology, we keep our publishing costs incredibly low—some books are priced as low as $4—making quality knowledge accessible to everyone.

Check out our book Golang Clean Code available on Amazon.

Stay tuned for updates and exciting news. When shopping for books, search for Aarav Joshi to find more of our titles. Use the provided link to enjoy special discounts!


📘 Checkout my latest ebook for free on my channel!
Be sure to like, share, comment, and subscribe to the channel!


Our Creations

Be sure to check out our creations:

Investor Central | Investor Central Spanish | Investor Central German | Smart Living | Epochs & Echoes | Puzzling Mysteries | Hindutva | Elite Dev | JS Schools


We are on Medium

Tech Koala Insights | Epochs & Echoes World | Investor Central Medium | Puzzling Mysteries Medium | Science & Epochs Medium | Modern Hindutva

Keywords: Next.js file uploads, UploadThing, Prisma, TypeScript, secure file handling



Similar Posts
Blog Image
How to Build SAML-Based Single Sign-On (SSO) with Node.js and Passport

Learn how to implement secure SAML SSO in your Node.js app using Passport.js and enterprise identity providers like Okta.

Blog Image
Next.js Prisma Integration Guide: Build Type-Safe Full-Stack Applications with Modern ORM

Learn how to integrate Next.js with Prisma ORM for type-safe full-stack applications. Build faster with seamless database interactions and end-to-end TypeScript support.

Blog Image
Build TypeScript Event Sourcing Systems with EventStore and Express - Complete Developer Guide

Learn to build resilient TypeScript systems with Event Sourcing, EventStoreDB & Express. Master CQRS, event streams, snapshots & microservices architecture.

Blog Image
Build Scalable WebRTC Video Conferencing: Complete Node.js, MediaSoup & Socket.io Implementation Guide

Learn to build scalable WebRTC video conferencing with Node.js, Socket.io & MediaSoup. Master SFU architecture, signaling & production deployment.

Blog Image
Build Real-Time Web Apps: Complete Svelte and Supabase Integration Guide for Modern Developers

Learn to integrate Svelte with Supabase for building real-time web applications. Master authentication, database operations, and live updates in this comprehensive guide.

Blog Image
Complete Guide to Integrating Next.js with Prisma ORM for Type-Safe Database Operations

Learn how to integrate Next.js with Prisma ORM for type-safe, scalable web apps. Discover setup steps, performance benefits & best practices today.