UploadThing
UploadThing via the uploadthing/server SDK. Auto-loads UPLOADTHING_TOKEN and maps your keys onto UploadThing's customId so operations route by your key.
Installation
uploadthing is an optional peer dependency of files-sdk - install alongside the SDK so the adapter’s imports resolve at runtime.
npm install files-sdk uploadthingpnpm add files-sdk uploadthingyarn add files-sdk uploadthingbun add files-sdk uploadthingUsage
UploadThing via the official uploadthing/server SDK. UploadThing generates its own internal file keys, so the adapter maps the user-supplied key onto UploadThing’s customId with defaultKeyType: "customId" - every subsequent operation routes by your key, not the auto-generated one.
import { Files } from "files-sdk";
import { uploadthing } from "files-sdk/uploadthing";
// UPLOADTHING_TOKEN is auto-loaded from env. The token is a base64
// JSON of { apiKey, appId, regions[] } - the adapter decodes it at
// construction so url() can synthesize the public CDN URL and
// signedUploadUrl() can sign a UFS PUT URL without an API round trip.
const files = new Files({
adapter: uploadthing({
// acl: "public-read", // default; switch to "private" to mint
// // signed URLs through generateSignedURL
// slug: "mediaUploader", // required only for signedUploadUrl()
}),
});
Options
token?string
UploadThing token. Falls back to `process.env.UPLOADTHING_TOKEN`. Tokens are base64-encoded JSON of the form `{ apiKey, appId, regions: string[] }` — the adapter decodes them at construction time so it can compute the public CDN host (`{appId}.ufs.sh`) and sign UFS presigned PUT URLs without an API round-trip. A token that doesn't decode to that shape throws immediately rather than failing later on the first call.
stringacl?"public-read" | "private"
ACL applied to uploads. Drives both the upload-time ACL and `url()` behavior — `"public-read"` returns the permanent CDN URL, `"private"` mints a short-lived signed URL via `generateSignedURL`. Defaults to `"public-read"`, which matches UploadThing's most common use case. Fixed at construction so a single `Files` instance is unambiguously one or the other. If you need both, instantiate two adapters.
"public-read" | "private"slug?string
UploadThing file-router slug. Required only by `signedUploadUrl()`, which embeds it as `x-ut-slug` on the ingest URL — UploadThing validates the upload against the route's config (allowed file types/sizes). Server-side `upload()` does not need it.
stringdefaultUrlExpiresIn?number
Default expiry (seconds) for signed download URLs and for `url()` when `acl` is `"private"`. UploadThing caps signed URLs at 7 days. Defaults to 3600 (1 hour).
numberdownloadTimeoutMs?number
Timeout in milliseconds for the HEAD/GET fallbacks that `head()`, `download()`, and lazy bodies returned from `list()` issue against the file URL. A hung CDN response would otherwise leak a fetch that never resolves. Defaults to 300_000 (5 minutes). Pass `0` to disable.
numberregion?string
Override the region alias used to construct the ingest URL for `signedUploadUrl()`. Defaults to the first region in the decoded token, or `"sea1"` if none is present.
stringCompatibility
| Method | Status | Notes |
|---|---|---|
upload |
⚠️ | User metadata and cacheControl aren’t supported by the UFS API, so passing either throws rather than silently dropping it. Resumable uploads (control) are not supported — UploadThing manages chunking server-side and exposes no resumable session. |
download |
✅ | |
delete |
✅ | |
list |
⚠️ | UploadThing’s listFiles is offset/limit, not cursor-based - the adapter encodes the next offset as a numeric cursor. prefix is unsupported server-side; the adapter filters the returned page client-side, which under-returns when the prefix isn’t satisfied within a single page. |
search |
⚠️ | Built on listAll — inherits this adapter’s list behavior above. Client-side key match (glob, regex, substring, exact). |
head |
⚠️ | UploadThing has no metadata endpoint, so head() issues a HEAD request against the resolved file URL (signed for private, CDN for public) and parses size/content-type/etag/last-modified from the response headers. User metadata isn’t supported. |
exists |
⚠️ | UploadThing has no metadata endpoint, so exists() issues a HEAD request against the resolved file URL (signed for private, CDN for public) and treats 404 as false. |
copy |
⚠️ | Read-then-write - UploadThing has no server-side copy primitive, so the source is downloaded and re-uploaded. Costs an egress + an ingest; not atomic. |
url |
⚠️ | Public adapters return the permanent CDN URL https://{appId}.ufs.sh/f/{key} and silently ignore expiresIn. Private adapters mint a signed read URL via generateSignedURL (1-hour default). responseContentDisposition throws either way - UploadThing has no Content-Disposition override on signed or CDN URLs. Use a private adapter for buckets with untrusted user-uploaded content. |
signedUploadUrl |
⚠️ | PUT URL only - built against UploadThing’s UFS ingest endpoint with an HMAC-SHA256 signature over the URL. maxSize is advisory: UploadThing enforces upload caps via the file-router config tied to the adapter’s slug, not via the URL signature. minSize is ignored (no equivalent on UFS). The user-supplied key is bound as x-ut-custom-id so subsequent ops can route by it. |