ZTS Docs

UploadThing Integration

How UploadThing is integrated for file uploads.

This document explains how UploadThing is integrated for handling file uploads, specifically focusing on single image uploads.

Configuration

  1. Enable Switch: Set NEXT_PUBLIC_ENABLE_UPLOADTHING to true. This client-side flag controls whether UploadThing features are active.

  2. API Key (Token/Secret): Provide your UploadThing Secret API Key in the UPLOADTHING_TOKEN environment variable.

  3. Environment Setup:

    • src/config/config.ts: Defines UPLOADTHING_URL_ROOT (used for constructing image URLs, this shouldn't be changed unless UploadThing changes something).

How it Works

  1. File Router (src/app/api/uploadthing/core.ts):

    • Defines the server-side logic for handling uploads using createUploadthing.
    • Currently includes one route: imageUploader, configured for single images up to 4MB.
    • Middleware: Contains authentication logic (auth).
    • onUploadComplete: Server-side callback after a successful upload. Currently logs information.
  2. API Route (src/app/api/uploadthing/route.ts):

    • Exports the Next.js App Router handlers (GET, POST) generated by createRouteHandler using the ourFileRouter.
  3. Client Upload Component (src/components/core/UploadThingUploadSingleImage):

    • A reusable React component for handling the upload UI and logic for a single image.
    • Uses the UploadButton generated by @uploadthing/react (src/server/uploadthing/uploadthing.ts).
    • Communicates with the /api/uploadthing endpoint.
    • Displays the uploaded image or the upload button.
    • Handles upload success (onClientUploadComplete) and errors (onUploadError).
    • Calls tRPC mutations (utImage.create, utImage.delete) after successful upload or before deletion to manage database records.
    • Includes a delete button to remove the image.
  4. Form Integration (src/components/FormFieldUploadThingImage.tsx):

    • A wrapper component to easily integrate UploadThingUploadSingleImage into react-hook-form forms.
    • Manages the form state for the image, which typically stores { id: string, key: string } | null.
  5. Database & Server Actions (src/server/api/routers/utImage.ts, src/server/uploadthing/server.ts):

    • A tRPC router (utImageRouter) handles creating and deleting image records in the database (UTImage model).
    • The create mutation associates the uploaded file's key with the authenticated user's ID.
    • The delete mutation removes the database record and uses utapi.deleteFiles(key) (from src/server/uploadthing/server.ts) to delete the actual file from UploadThing storage.
    • The UTApi instance in server.ts uses the UPLOADTHING_TOKEN for server-side actions.

    Why store image metadata in our database?

    Storing a reference (key, userId, etc.) to the uploaded image in our own UTImage table serves several purposes:

    • Association: It allows us to directly link an uploaded image to a specific user or another data model within our application (e.g., linking an avatar image key to a User record).
    • Ownership & Security: We can easily verify ownership before allowing actions like deletion.
    • Cleanup & Orphan Prevention: By having a record in our database, we ensure that we don't lose track of images uploaded to UploadThing. This makes cleanup easier. For example, a periodic cleanup job (e.g., a cron job) could query the UTImage table for old or unassociated images and then call the UploadThing API (utapi.deleteFiles) to remove them, preventing orphaned files in UploadThing storage without needing to constantly list all files via the UploadThing API.

Usage

Typically, you would use the FormFieldUploadThingImage component within a form where a user needs to upload a single image (like a profile picture or cover image):

import { FormFieldUploadThingImage } from "@/components/FormFieldUploadThingImage";
 
// Inside your react-hook-form component
<FormFieldUploadThingImage
  name="profileImage" // Name of the field in your form schema
  endpoint="imageUploader"
  label="Profile Picture"
  description="Upload a profile picture (Max 4MB)."
/>;

On this page