Master UploadThing file uploads for Google Antigravity IDE applications
# UploadThing File Upload Patterns for Google Antigravity IDE
Implement secure file uploads with UploadThing using Google Antigravity IDE. This comprehensive guide covers file routing, validation, callbacks, progress tracking, and integration patterns for Next.js applications.
## Core Configuration
```typescript
// src/lib/uploadthing.ts
import { createUploadthing, type FileRouter } from "uploadthing/next";
import { getServerSession } from "next-auth";
import { authOptions } from "./auth";
import { db } from "./db";
import { UploadThingError } from "uploadthing/server";
const f = createUploadthing();
// Auth middleware
const auth = async () => {
const session = await getServerSession(authOptions);
if (!session?.user) throw new UploadThingError("Unauthorized");
return { userId: session.user.id };
};
export const uploadRouter = {
// Profile avatar upload
avatar: f({ image: { maxFileSize: "4MB", maxFileCount: 1 } })
.middleware(auth)
.onUploadComplete(async ({ metadata, file }) => {
await db.user.update({
where: { id: metadata.userId },
data: { avatarUrl: file.url },
});
return { uploadedBy: metadata.userId, url: file.url };
}),
// Post cover images
coverImage: f({ image: { maxFileSize: "8MB", maxFileCount: 1 } })
.middleware(async () => {
const { userId } = await auth();
const canUpload = await checkUploadQuota(userId);
if (!canUpload) throw new UploadThingError("Upload quota exceeded");
return { userId };
})
.onUploadComplete(async ({ metadata, file }) => {
await db.upload.create({
data: {
userId: metadata.userId,
url: file.url,
key: file.key,
type: "cover",
size: file.size,
},
});
return { url: file.url };
}),
// Document uploads with PDF support
documents: f({
pdf: { maxFileSize: "16MB", maxFileCount: 5 },
"application/msword": { maxFileSize: "16MB", maxFileCount: 5 },
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": {
maxFileSize: "16MB",
maxFileCount: 5,
},
})
.middleware(async () => {
const { userId } = await auth();
return { userId };
})
.onUploadComplete(async ({ metadata, file }) => {
// Process document (e.g., extract text for search)
await processDocument(file.url, file.key);
return { url: file.url, key: file.key };
}),
// Video uploads with longer processing
videos: f({ video: { maxFileSize: "512MB", maxFileCount: 1 } })
.middleware(async () => {
const { userId } = await auth();
const subscription = await getSubscription(userId);
if (subscription?.plan !== "pro") {
throw new UploadThingError("Video uploads require Pro subscription");
}
return { userId };
})
.onUploadComplete(async ({ metadata, file }) => {
// Queue video processing job
await inngest.send({
name: "video/uploaded",
data: {
userId: metadata.userId,
url: file.url,
key: file.key,
},
});
return { url: file.url, processing: true };
}),
} satisfies FileRouter;
export type OurFileRouter = typeof uploadRouter;
```
## React Component Integration
```typescript
// src/components/FileUploader.tsx
"use client";
import { useCallback, useState } from "react";
import { useDropzone } from "@uploadthing/react";
import { useUploadThing } from "@/lib/uploadthing-react";
import { generateClientDropzoneAccept } from "uploadthing/client";
interface FileUploaderProps {
endpoint: keyof OurFileRouter;
onUploadComplete?: (urls: string[]) => void;
onUploadError?: (error: Error) => void;
maxFiles?: number;
}
export function FileUploader({
endpoint,
onUploadComplete,
onUploadError,
maxFiles = 1,
}: FileUploaderProps) {
const [files, setFiles] = useState<File[]>([]);
const [uploadProgress, setUploadProgress] = useState<Record<string, number>>({});
const { startUpload, isUploading, permittedFileInfo } = useUploadThing(endpoint, {
onClientUploadComplete: (res) => {
setFiles([]);
setUploadProgress({});
onUploadComplete?.(res.map((r) => r.url));
},
onUploadError: (error) => {
onUploadError?.(error);
},
onUploadProgress: (progress) => {
setUploadProgress((prev) => ({
...prev,
[progress.file]: progress.progress,
}));
},
});
const onDrop = useCallback(
(acceptedFiles: File[]) => {
setFiles(acceptedFiles.slice(0, maxFiles));
},
[maxFiles]
);
const { getRootProps, getInputProps, isDragActive } = useDropzone({
onDrop,
accept: permittedFileInfo?.config
? generateClientDropzoneAccept(permittedFileInfo.config)
: undefined,
maxFiles,
});
return (
<div className="upload-container">
<div
{...getRootProps()}
className={`dropzone ${isDragActive ? "active" : ""}`}
>
<input {...getInputProps()} />
{isDragActive ? (
<p>Drop files here...</p>
) : (
<p>Drag & drop files, or click to select</p>
)}
</div>
{files.length > 0 && (
<div className="file-list">
{files.map((file) => (
<div key={file.name} className="file-item">
<span>{file.name}</span>
{uploadProgress[file.name] !== undefined && (
<div className="progress-bar">
<div
className="progress"
style={{ width: `${uploadProgress[file.name]}%` }}
/>
</div>
)}
</div>
))}
<button
onClick={() => startUpload(files)}
disabled={isUploading}
>
{isUploading ? "Uploading..." : "Upload"}
</button>
</div>
)}
</div>
);
}
```
## Best Practices for Google Antigravity IDE
When using UploadThing with Google Antigravity, define strict file type and size limits. Implement authentication middleware for all routes. Use onUploadComplete for database updates. Add quota checking for user limits. Process files asynchronously for large uploads. Let Gemini 3 generate file router configurations from your requirements.
Google Antigravity excels at scaffolding complete upload flows with proper validation.This UploadThing prompt is ideal for developers working on:
By using this prompt, you can save hours of manual coding and ensure best practices are followed from the start. It's particularly valuable for teams looking to maintain consistency across their uploadthing implementations.
Yes! All prompts on Antigravity AI Directory are free to use for both personal and commercial projects. No attribution required, though it's always appreciated.
This prompt works excellently with Claude, ChatGPT, Cursor, GitHub Copilot, and other modern AI coding assistants. For best results, use models with large context windows.
You can modify the prompt by adding specific requirements, constraints, or preferences. For UploadThing projects, consider mentioning your framework version, coding style, and any specific libraries you're using.