UploadThing: A Modern File Upload Solution for Next.js Applications
January 11, 2025 (2d ago)
Introduction
UploadThing is an open-source file upload solution specifically designed for Next.js applications. It provides developers with a type-safe, efficient way to handle file uploads while offering features like file validation, transformation, and direct integration with popular frameworks.
Technical Overview
At its core, UploadThing consists of three main components:
Server-side file router
Client-side components and hooks
Type-safe API endpoints
Installation and Basic Setup
First, install the required packages:
Create a file router (typically in app/api/uploadthing/core.ts):
These are the routes you create with the helper instantiated by createUploadthing. Think of them as the "endpoints" for what your users can upload. An object with file routes constructs a file router where the keys (slugs) in the object are the names of your endpoints.
Route Config:
The f function takes two arguments. The first can be an array of FileType, or a record mapping each FileType with a route config. The route config allow more granular control, for example what files can be uploaded and how many of them can be uploaded for a given upload. The array syntax will fallback to applying the defaults to all file types.
A FileType can be any valid web MIME type ↗. For example: use application/json to only allow JSON files to be uploaded.
Additionally, you may pass any of the following custom types: image, video, audio, pdf or text. These are shorthands that allows you to specify the type of file without specifying the exact MIME type. Lastly, there's blob which allows any file type.
Route Options:
The second argument to the f function is an optional object of route options. These configurations provide global settings that affect how the upload route behaves.
Available route options:
awaitServerData: (boolean, default: false)
When set to true, the client will wait for the server's onUploadComplete handler to finish and return data before running onClientUploadComplete. This is useful when you need to ensure server-side processing is complete before proceeding with client-side operations.
Example:
Route Methods
The f function returns a builder object that allows you to chain the following methods:
input
Validates user input from the client using schema validators. This method ensures that any additional data sent alongside the file upload meets your specifications.
Supported validators:
Zod (≥3)
Effect/Schema (≥3.10, with limitations)
Standard Schema specification (e.g., Valibot ≥1.0, ArkType ≥2.0)
Example with complex validation:
middleware
Handles authorization and metadata tagging. This is where you perform authentication checks and prepare any data needed for the upload process.
Example with comprehensive auth and metadata:
onUploadError
Called when an upload error occurs. Use this to handle errors gracefully and perform any necessary cleanup or logging.
Parameters:
error: UploadThingError (contains error message and code)
fileKey: string (unique identifier for the failed upload)
Example:
onUploadComplete
Final handler for successful uploads. This is where you can process the uploaded file and perform any necessary post-upload operations.
Parameters:
metadata: Data passed from middleware
file: UploadedFileData object containing:
name: Original file name
size: File size in bytes
key: Unique file identifier
url: Public URL of the uploaded file
Example with comprehensive handling:
Uploading Files
UploadThing provides two primary methods for uploading files: Client-Side Uploads and Server-Side Uploads. Each approach has its own benefits and use cases.
Client-Side Uploads
Client-side uploads are the recommended approach as they offer several advantages:
Reduced server costs (no ingress/egress fees)
Direct file transfer to UploadThing
Built-in validation and type safety
The process works as follows:
Client initiates upload request
Server generates presigned URLs
Client uploads directly to UploadThing
Server receives callback on completion
Example implementation using React:
Server-Side Uploads
Server-side uploads are useful when you need to:
Process or validate files before uploading
Generate files on the server
Handle specific security requirements
Example using the UTApi:
Upload Configuration
Both client and server uploads support various configuration options:
File Validation:
Custom Metadata:
Upload Callbacks:
Resumable Uploads
UploadThing supports resumable uploads for large files:
Security Considerations
URL Signing: All upload URLs are signed with your API key and include expiration timestamps
File Validation: Implement thorough validation in your file routes
Authentication: Always use middleware to authenticate users before allowing uploads
Example secure configuration:
Working with Files
After successfully uploading files to UploadThing, there are several ways to work with and access these files. Here's a comprehensive guide on file operations.
Accessing Public Files
Files are served through UploadThing's CDN using the following URL pattern:
https://<APP_ID>.ufs.sh/f/<FILE_KEY>
If you've set a customId during upload, you can also access files using:
https://<APP_ID>.ufs.sh/f/<CUSTOM_ID>
Important: Never use raw storage provider URLs (e.g., https://bucket.s3.region.amazonaws.com/<FILE_KEY>). UploadThing may change storage providers or buckets, making these URLs unreliable.
Setting Up Image Optimization (Next.js Example)
UTApi Reference
The UploadThing API Helper is designed for server-side use. While it provides a REST API interface, it offers enhanced functionality and type safety.
Note: External API calls will typically be slower than querying your own database. It's recommended to store necessary file data in your database, either in onUploadComplete() or after using uploadFiles(), rather than relying on the API for core data flow.
Constructor
Initialize an instance of UTApi:
Configuration Options:
fetch: Custom fetch function
token: Your UploadThing token (default: env.UPLOADTHING_TOKEN)
logFormat: Log format (json | logFmt | structured | pretty)
defaultKeyType: Default key type for file operations ('fileKey' | 'customId')
apiUrl: UploadThing API URL (default: https://api.uploadthing.com)
ingestUrl: UploadThing Ingest API URL
File Operations
Upload Files
Upload Files from URL
Delete Files
List Files
Rename Files
Get Signed URL
Update ACL
Accessing Private Files
For files protected by access controls, you'll need to generate short-lived presigned URLs. There are two ways to do this:
Using UTApi:
Using REST API Endpoint:
File Operations
The UTApi provides several methods for managing files:
Deleting Files:
Checking File Status:
Renaming Files:
Best Practices
URL Management:
Always use the CDN URLs provided by UploadThing
Store file keys rather than full URLs in your database
Generate presigned URLs on-demand for private files
Security:
Implement proper access controls in your middleware
Use short expiration times for presigned URLs
Validate file access permissions before generating signed URLs
Performance:
Utilize the CDN for optimal file delivery
Consider implementing caching for frequently accessed files
Use appropriate image optimization settings
Example implementation combining these practices:
Conclusion
UploadThing provides a robust, type-safe solution for handling file uploads in Next.js applications. Its key strengths include:
Developer Experience: Type-safe APIs and intuitive integration with React components
Flexibility: Support for both client and server-side uploads with customizable workflows
Security: Built-in file validation, access controls, and secure URL signing
Performance: CDN-backed delivery and resumable uploads for large files
Whether you're building a simple image upload feature or a complex file management system, UploadThing offers the tools and flexibility needed to implement secure and efficient file handling in your applications.