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 Type | Default Max Size |
---|---|
image | 4MB |
video | 16MB |
audio | 8MB |
blob | 8MB |
4MB | |
text | 64kB |
MimeType | 4MB |
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.
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.
Arguments | Type | Required | Description |
---|---|---|---|
files | FileEsque || FileEsque[] | Yes | The file(s) you want to upload |
metadata | Json | No | Metadata to attach to the file(s) |
contentDisposition | "inline" | "attachment" | No | What 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[]
Arguments | Type | Required | Description |
---|---|---|---|
urls | URL || string || (URL || string)[] | Yes | The URL(s) of the file(s) you wish to upload |
metadata | Json | No | Metadata to attach to the file(s) |
contentDisposition | "inline" | "attachment" | No | What 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",
]);
Arguments | Type | Required | Notes | Description |
---|---|---|---|---|
input | string || string[] | Yes | Added in v5.0 | The 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",
]);
Arguments | Type | Required | Notes | Description |
---|---|---|---|---|
input | string || string[] | Yes | Added in v5.0 | The 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 Rename
s 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
};
Arguments | Type | Required | Description |
---|---|---|---|
renames | Rename || Rename[] | Yes | Object specifying what file to rename and the new name |