Working with Files

After your files have been uploaded, you will most likely want to do something with them. This page shows how to work with your uploaded files.

Accessing Public Files

UploadThing serves all files from a CDN at the following URL pattern:

https://<APP_ID>.ufs.sh/f/<FILE_KEY>

If you set a customId when uploading the file, you can also use https://<APP_ID>.ufs.sh/f/<CUSTOM_ID> to access it.

Given that all files are served from a subdomain of your app, you have granular control over what URLs are allowed to be processed. Below is an example of how to setup image optimization allow filtering in Next.js that only allows optimizing images from your app:

/** @type {import('next').NextConfig} */
export default {
  images: {
    remotePatterns: [
      {
        protocol: "https",
        hostname: "<APP_ID>.ufs.sh",
        pathname: "/f/*",
      },
    ],
  },
};

Accessing Private Files

If your files are protected with access controls, you can generate a presigned URL using UTApi.getSignedUrl. Here's a reference implementation using Node.js crypto:

import crypto from "node:crypto";

const apiKey = "sk_live_...";
const url = new URL("https://<APP_ID>.ufs.sh/f/<FILE_KEY>");
const algorithm = "hmac-sha256";

// Set expiration to 30 seconds from now (you choose how long you want the URL to be valid for)
const expires = Date.now() + 1000 * 30;
url.searchParams.set("expires", String(expires));

const signature = crypto
  .createHmac(algorithm, apiKey)
  .update(url.href)
  .digest("hex");
url.searchParams.set("signature", `${algorithm}=${signature}`);

// The URL is now signed and ready to use
await fetch(url); // Status 200 OK

The URL will be valid for the duration in milliseconds you set in the expires parameter or until the API key is deleted or revoked.

The presigned URL follows the same patterns as public files, with additional query parameters to authenticate the request.

Other File Operations

Please refer to our server SDK, UTApi for more information on how to work with files. You can also access the API directly using the OpenAPI Specification.

Was this page helpful?