API Reference
Server

createUploadthing

The helper function to create an UploadThing instance. MAKE SURE YOU IMPORT IT FROM THE RIGHT PLACE

import { createUploadthing, type FileRouter } from "uploadthing/next";
 
const f = createUploadthing();
export const uploadRouter = { ... };

File Routes

File Routes are the routes you create with the helped instantiated by createUploadthing. Think of them as the "endpoints" for what your users can upload. The keys in the object are the names of your endpoints.

import { createUploadthing, type FileRouter } from "uploadthing/next";
 
const f = createUploadthing();
 
export const ourFileRouter = {
  // Example "profile picture upload" route - these can be named whatever you want!
  profilePicture: f(["image"])
    .middleware(({ req }) => auth(req))
    .onUploadComplete((data) => console.log("file", data)),
 
  // This route takes an attached image OR video
  messageAttachment: f(["image", "video"])
    .middleware(({ req }) => auth(req))
    .onUploadComplete((data) => console.log("file", data)),
 
  // Takes ONE image up to 2MB
  strictImageAttachment: f({ image: { maxFileSize: "2MB", maxFileCount: 1 } })
    .middleware(({ req }) => auth(req))
    .onUploadComplete((data) => console.log("file", data)),
 
  // Takes a 4 2mb images and/or 1 256mb video
  mediaPost: f({
    image: { maxFileSize: "2MB", maxFileCount: 4 },
    video: { maxFileSize: "256MB", maxFileCount: 1 },
  })
    .middleware(({ req }) => auth(req))
    .onUploadComplete((data) => console.log("file", data)),
} satisfies FileRouter;
 
export type OurFileRouter = typeof ourFileRouter;

Input

// Your file types can be any of the following types
type MimeType = /** any web mime-type */
type ValidFileTypes = "image" | "video" | "audio" | "blob" | "pdf" | "text" | MimeType;
type ContentDisposition = "inline" | "attachment";
 
// The input to your f() function can be an array of file types OR an object of them w/ config
type FileRouterInput =
  | ValidFileTypes[]
  | {
      [key: ValidFileTypes]: {
        maxFileSize?: string;
        maxFileCount?: number;
        contentDisposition?: ContentDisposition = "inline";
      };
    };

The contentDisposition option can be used to override the default inline disposition set at the storage provider. This is useful if you want your files downloaded instead of previewed in the browser. You can read more about content disposition on MDN ↗ (opens in a new tab).

Defaults

All routes default to a max file count of 1. The file size defaults are below

File TypeDefault Max Size
image4MB
video16MB
audio8MB
blob8MB
pdf4MB
text64kB
MimeType4MB

input

You can pass a zod schema to validate user input from the client. This data comes from the client when the upload starts. If validation here fails, an error will be thrown and none of your middleware n'or onUploadComplete functions will be executed.

The input is validated on your server and only leaves your server if you pass it along from the .middleware to the .onUploadComplete. If you only use the input in the middleware without returning it, the Uploadthing server won't have any knowledge of it.

import { z } from "zod";
 
f(["image"])
  .input(z.object({ foo: z.string() }))
  .middleware(async ({ req, input }) => {
    input;
    // ^? { foo: string }
    return {};
  })
  .onUploadComplete(async () => {});

middleware

This is the function where you authorize a user to do an upload. You can also tag the upload with metadata here. Example using Clerk:

import { currentUser } from "@clerk/nextjs";
 
f(["image"])
  .middleware(async ({ req, res }) => {
    const user = await currentUser();
 
    // Throw if user isn't signed in
    if (!user)
      throw new Error("You must be logged in to upload a profile picture");
 
    // Return userId to be used in onUploadComplete
    return { userId: user.id };
  })
  .onUploadComplete(async ({ metadata }) => {
    console.log("Uploaded by user", metadata.userId);
  });

onUploadComplete

This is the function you use to do something with the uploaded file, such as persisting it to your database. Whatever you returned in the middleware will be accessible here.

As of v6.0, you can return JSON serializable data from this function, which will be passed to the clientside onClientUploadComplete callback.

UTApi

The UploadThing API Helper, for use ON YOUR SERVER. It's basically just a REST API but better.

To get started, initialize an instance of UTApi.

Prior to v5.7, this was exported as a regular object called utapi without any custom intialization support.

~/server/uploadthing.ts
import { UTApi } from "uploadthing/server";
 
export const utapi = new UTApi();

The constructor takes some optional arguments that you can pass to override the defaults. Below are shown the available options, the default values, and the types of the values.

{
  fetch: FetchEsque = globalThis.fetch; // subset of standard fetch required for uploadthing
  apiKey: string = process.env.UPLOADTHING_SECRET;
}

uploadFiles

Added in v5.3

Upload files directly from your server without using the file router. Useful for server-side file processing, uploading from a server action, and much more.

import { utapi } from "~/server/uploadthing.ts";
 
async function uploadFiles(formData: FormData) {
  "use server";
  const files = formData.getAll("files");
  const response = await utapi.uploadFiles(files);
  //    ^? UploadedFileResponse[]
}
 
function MyForm() {
  return (
    <form action={uploadFiles}>
      <input name="files" type="file" multiple />
      <button type="submit">Upload</button>
    </form>
  );
}

When uploading files using uploadFiles, the files must be present on your server. Then presigned URLs are generated on our servers before the files can be uploaded to the storage provider.

ArgumentsTypeRequiredDescription
filesFileEsque || FileEsque[]YesThe file(s) you want to upload
metadataJsonNoMetadata to attach to the file(s)
contentDisposition"inline" | "attachment"NoWhat content disposition (opens in a new tab) should be set on the storage provider. Defaults to inline
// Edge / Node < 20 friendly File interface
interface FileEsque extends Blob {
  name: string;
}

The returned UploadedFileResponse is an object with the following shape. If the files argument is an array, the returned value will be of type UploadedFileResponse[].

type UploadFileResponse =
  | { data: UploadData; error: null }
  | { data: null; error: UploadError };
 
type UploadData = {
  key: string;
  url: string;
  name: string;
  size: number;
};
 
type UploadError = {
  code: string;
  message: string;
  data: any;
};

uploadFilesFromUrl

Added in v5.3

Have a file hosted somewhere else you want to upload on UploadThing? This is the function you're looking for.

⚠️

When uploading files from URL, the file is first downloaded on your server, before presigned URLs are created and the file is uploaded to the storage provider.

import { utapi } from "~/server/uploadthing.ts";
 
const fileUrl = "https://test.com/some.png";
const uploadedFile = await utapi.uploadFilesFromUrl(fileUrl);
//    ^? UploadedFileResponse
 
const fileUrls = ["https://test.com/some.png", "https://test.com/some2.png"];
const uploadedFiles = await utapi.uploadFilesFromUrl(fileUrls);
//    ^? UploadedFileResponse[]
ArgumentsTypeRequiredDescription
urlsURL || string || (URL || string)[]YesThe URL(s) of the file(s) you wish to upload
metadataJsonNoMetadata to attach to the file(s)
contentDisposition"inline" | "attachment"NoWhat content disposition (opens in a new tab) should be set on the storage provider. Defaults to inline

deleteFiles

Added in v4.0

deleteFiles takes in a fileKey or an array of fileKeys and deletes them from the server.

import { utapi } from "~/server/uploadthing.ts";
 
await utapi.deleteFiles("2e0fdb64-9957-4262-8e45-f372ba903ac8_image.jpg");
await utapi.deleteFiles([
  "2e0fdb64-9957-4262-8e45-f372ba903ac8_image.jpg",
  "1649353b-04ea-48a2-9db7-31de7f562c8d_image2.jpg",
]);
ArgumentsTypeRequiredNotesDescription
inputstring || string[]YesAdded in v5.0The fileKey or fileKeys you want to delete

getFileUrls

Added in v4.0

getFileUrls takes in a fileKey or an array of fileKeys and returns the URLs to access them.

import { utapi } from "~/server/uploadthing.ts";
 
const oneUrl = await utapi.getFileUrls(
  "2e0fdb64-9957-4262-8e45-f372ba903ac8_image.jpg",
);
const multipleUrls = await utapi.getFileUrls([
  "2e0fdb64-9957-4262-8e45-f372ba903ac8_image.jpg",
  "1649353b-04ea-48a2-9db7-31de7f562c8d_image2.jpg",
]);
ArgumentsTypeRequiredNotesDescription
inputstring || string[]YesAdded in v5.0The fileKey or fileKeys you want to get URLs for

listFiles

Added in v5.3

listFiles takes no input and returns an array of objects containing file ids and keys for all files that have been uploaded to the application your API key corresponds to.

import { utapi } from "~/server/uploadthing.ts";
 
const files = await utapi.listFiles();
 
console.log(files);
/*
 * [
 *  {
 *    id: "2e0fdb64-9957-4262-8e45-f372ba903ac8",
 *    key: "2e0fdb64-9957-4262-8e45-f372ba903ac8_image.jpg"
 *  }
 * ]
 */

renameFiles

Added in v5.3

renameFiles takes in a Rename or an array of Renames and renames the appropriate files on the server.

import { utapi } from "~/server/uploadthing.ts";
 
await utapi.renameFiles({
  fileKey: "2e0fdb64-9957-4262-8e45-f372ba903ac8_image.jpg",
  newName: "myImage.jpg",
});
 
await utapi.renameFiles([
  {
    fileKey: "2e0fdb64-9957-4262-8e45-f372ba903ac8_image.jpg",
    newName: "myImage.jpg",
  },
  {
    fileKey: "1649353b-04ea-48a2-9db7-31de7f562c8d_image2.jpg",
    newName: "myOtherImage.jpg",
  },
]);

Rename type definition

type Rename = {
  fileKey: string;
  newName: string; // should include file extension
};
ArgumentsTypeRequiredDescription
renamesRename || Rename[]YesObject specifying what file to rename and the new name