UploadThing is the file upload library built for TypeScript. It handles presigned URLs, validation, and storage — so you just define what files you accept.
Define Upload Routes
import { createUploadthing, type FileRouter } from "uploadthing/next";
const f = createUploadthing();
export const uploadRouter = {
imageUploader: f({ image: { maxFileSize: "4MB", maxFileCount: 4 } })
.middleware(async ({ req }) => {
const user = await auth(req);
if (!user) throw new Error("Unauthorized");
return { userId: user.id };
})
.onUploadComplete(async ({ metadata, file }) => {
console.log("Upload complete:", file.url);
await db.insert({ userId: metadata.userId, fileUrl: file.url });
}),
csvUploader: f({ "text/csv": { maxFileSize: "16MB" } })
.middleware(async () => ({ uploadedAt: new Date() }))
.onUploadComplete(({ file }) => {
console.log("CSV uploaded:", file.name, file.size);
}),
documentUploader: f({ pdf: { maxFileSize: "8MB" }, image: { maxFileSize: "4MB" } })
.onUploadComplete(({ file }) => console.log(file.url)),
} satisfies FileRouter;
React Component: Drop Zone
import { UploadButton, UploadDropzone } from "@uploadthing/react";
import type { uploadRouter } from "./uploadthing";
function UploadPage() {
return (
<div>
{/* Simple button */}
<UploadButton
endpoint="imageUploader"
onClientUploadComplete={(res) => {
console.log("Files:", res.map(f => f.url));
}}
onUploadError={(error) => alert(error.message)}
/>
{/* Drag and drop zone */}
<UploadDropzone
endpoint="csvUploader"
onClientUploadComplete={(res) => {
console.log("CSV uploaded:", res[0].url);
}}
/>
</div>
);
}
useUploadThing Hook: Full Control
import { useUploadThing } from "@uploadthing/react";
function CustomUpload() {
const { startUpload, isUploading, permittedFileInfo } = useUploadThing("imageUploader", {
onClientUploadComplete: (res) => console.log(res),
onUploadError: (e) => console.error(e),
onUploadProgress: (p) => console.log(`${p}%`),
});
return (
<input
type="file"
onChange={async (e) => {
const files = Array.from(e.target.files || []);
await startUpload(files);
}}
/>
);
}
Server-Side: generateReactHelpers
import { generateReactHelpers } from "@uploadthing/react";
import type { uploadRouter } from "./uploadthing";
export const { useUploadThing, uploadFiles } = generateReactHelpers<typeof uploadRouter>();
// Upload from server
import { utapi } from "uploadthing/server";
const uploaded = await utapi.uploadFiles(file);
const url = uploaded.data.url;
// Delete files
await utapi.deleteFiles(["file-key-1", "file-key-2"]);
// Get file URLs
const urls = await utapi.getFileUrls(["key1", "key2"]);
Upload scraped data files? My Apify tools + UploadThing = seamless data export.
Custom upload solution? Email spinov001@gmail.com
Top comments (0)