UploadThing mit Claude Code: File Uploads fuer Next.js 2026
UploadThing macht File Uploads in Next.js trivial — kein S3-Setup, keine Presigned URLs manuell, kein CORS-Gefummel. Claude Code generiert vollstaendige Upload-Infrastruktur mit Validation, Auth und Callbacks.
File Router: Server-seitige Upload-Konfiguration
RouterUpload-Endpoints mit Validation
# Prompt: "Erstelle UploadThing-Setup fuer Avatar und Dokument-Uploads"
npm install uploadthing @uploadthing/react
// server/uploadthing.ts — File Router
import { createUploadthing, type FileRouter } from "uploadthing/next";
import { auth } from "@/lib/auth";
const f = createUploadthing();
export const ourFileRouter = {
// Avatar: nur Bilder, max 4MB
avatarUploader: f({ image: { maxFileSize: "4MB", maxFileCount: 1 } })
.middleware(async ({ req }) => {
const session = await auth();
if (!session) throw new Error("Unauthorized");
return { userId: session.user.id }; // In onUploadComplete verfuegbar
})
.onUploadComplete(async ({ metadata, file }) => {
await db.user.update({
where: { id: metadata.userId },
data: { avatarUrl: file.url },
});
return { uploadedBy: metadata.userId };
}),
// Dokument-Upload: PDF und Office, max 32MB
documentUploader: f({
pdf: { maxFileSize: "32MB" },
"application/msword": { maxFileSize: "32MB" },
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": { maxFileSize: "32MB" },
})
.middleware(async ({ req }) => {
const session = await auth();
if (!session) throw new Error("Unauthorized");
return { userId: session.user.id };
})
.onUploadComplete(async ({ metadata, file }) => {
await db.document.create({
data: { name: file.name, url: file.url, userId: metadata.userId },
});
}),
} satisfies FileRouter;
export type OurFileRouter = typeof ourFileRouter;
// app/api/uploadthing/route.ts
import { createRouteHandler } from "uploadthing/next";
export const { GET, POST } = createRouteHandler({ router: ourFileRouter });
Client-seitige Upload-Komponenten
ClientUploadButton und UploadDropzone
// utils/uploadthing.ts — typisierte Client-Hilfsfunktionen
import { generateUploadButton, generateUploadDropzone } from "@uploadthing/react";
import type { OurFileRouter } from "@/server/uploadthing";
export const UploadButton = generateUploadButton<OurFileRouter>();
export const UploadDropzone = generateUploadDropzone<OurFileRouter>();
// AvatarUpload.tsx
function AvatarUpload({ onUpload }: { onUpload: (url: string) => void }) {
return (
<UploadButton
endpoint="avatarUploader"
onClientUploadComplete={(res) => {
const url = res[0]?.url;
if (url) onUpload(url);
toast.success("Bild hochgeladen!");
}}
onUploadError={(err) => toast.error(`Upload fehlgeschlagen: ${err.message}`)}
appearance={{
button: "bg-indigo-600 hover:bg-indigo-700 text-white px-4 py-2 rounded",
allowedContent: "text-gray-500 text-sm",
}}
/>
);
}
// Dropzone fuer Dokumente:
<UploadDropzone
endpoint="documentUploader"
onClientUploadComplete={(res) => {
setDocuments(prev => [...prev, ...res.map(f => ({ name: f.name, url: f.url }))]);
}}
onUploadProgress={(p) => setProgress(p)} // 0-100
className="border-2 border-dashed border-gray-300 rounded-lg p-8"
/>
Styling-Tipp: UploadButton/Dropzone akzeptieren
appearance Prop fuer CSS-Klassen oder Style-Objekte. Claude Code passt das Styling automatisch an Tailwind-Klassen an.useUploadThing Hook fuer Custom UI
HookVolle Kontrolle mit useUploadThing
# Prompt: "Custom Drag-and-Drop UI mit Fortschrittsbalken"
import { useUploadThing } from "@uploadthing/react";
function CustomUploader() {
const [files, setFiles] = useState<File[]>([]);
const [progress, setProgress] = useState(0);
const { startUpload, isUploading } = useUploadThing("documentUploader", {
onClientUploadComplete: (res) => {
console.log("Uploaded:", res);
setFiles([]);
setProgress(0);
},
onUploadProgress: setProgress,
onUploadError: (err) => console.error(err),
});
return (
<div
onDrop={(e) => {
e.preventDefault();
setFiles(Array.from(e.dataTransfer.files));
}}
onDragOver={(e) => e.preventDefault()}
>
{files.length > 0 && (
<div>
{files.map(f => <div key={f.name}>{f.name}</div>)}
<button onClick={() => startUpload(files)} disabled={isUploading}>
{isUploading ? `${progress}%` : "Hochladen"}
</button>
</div>
)}
</div>
);
}
File-Handling im Kurs
Im Claude Code Mastery Kurs: vollstaendiges File-Upload-Modul mit UploadThing, S3/R2 direkt und Image-Processing — inkl. Virus-Scanning, CDN-Integration und Multi-File-Workflows.
14 Tage kostenlos testen →