url
Return a URL to fetch a key - a signed GetObject where the adapter can sign, or a direct CDN/public URL where one is configured.
files.url(key, options?)
Returns a URL the caller can use to fetch key. Every adapter returns the most direct URL it can produce. Signing adapters (S3 and the S3-compatible catalog — R2 over HTTP plus every regional / budget / decentralised wrapper — alongside Google Cloud Storage, Firebase Storage, Azure (shared-key or user-delegation SAS), Supabase, UploadThing in private mode, Vercel Blob in access: "private" mode, and the R2 binding when HTTP credentials are also configured) sign a read URL - defaulting to a 1-hour expiry, override per-call via { expiresIn } or per-adapter via defaultUrlExpiresIn. If the adapter is constructed with a publicBaseUrl (CDN, custom domain, r2.dev, Bunny Pull Zone) or UploadThing’s public-read ACL, a plain url(key) returns that permanent link without signing (capabilities.publicUrl is true).
expiresIn always means “give me a link that expires”. On an adapter that can sign, passing it returns a signed URL even when a publicBaseUrl is configured. On one that can’t (Vercel Blob in public mode, UploadThing public-read, Convex, Appwrite, the filesystem), it throws an Unsupported FilesError rather than handing back a permanent link that ignores it. Leave it out to get the adapter’s default. expiresIn is a whole number of seconds: 0, a negative or fractional value, or NaN throws an Invalid FilesError before anything is signed, instead of returning a URL that never works.
Adapters with no URL primitive throw unless you configure a public URL for them: an R2 Workers binding without either publicBaseUrl or HTTP credentials; Bunny Storage, FTP, SFTP, and WebDAV without publicBaseUrl; Google Drive, OneDrive, and SharePoint without publicByDefault: true; and Appwrite without public: true. Netlify Blobs has no URL primitive at all, so url() always throws there. Provider gaps covers each one, and files.capabilities.signedUrl tells you up front whether the adapter can sign.
// One call, every adapter. S3 and the S3-compatible catalog (R2 over HTTP
// plus every regional / budget / decentralised wrapper) sign a GetObject (1h
// default, override with { expiresIn }); Google Cloud Storage and Azure sign
// a read URL natively with the same default; Supabase signs via createSignedUrl
// (or returns the public URL when constructed with public:true); Vercel Blob
// (public), UploadThing (public-read), and Bunny Storage with publicBaseUrl
// return their CDN URLs. If you configured `publicBaseUrl` on the adapter, a
// plain url() returns that permanent link.
const url = await files.url("avatars/abc.png");
// An expiring link: signed even when `publicBaseUrl` is set; an `Unsupported`
// error on an adapter that only has permanent links.
const short = await files.url("avatars/abc.png", { expiresIn: 60 });
// Force download (defeat stored XSS from user-uploaded HTML/SVG).
// Forces signing even if `publicBaseUrl` is configured - a permanent
// CDN URL has no signature to bind the override into, and silently
// dropping a security ask would be a regression.
const safe = await files.url("avatars/abc.png", {
responseContentDisposition: "attachment",
});
Options
expiresIn?number
Ask for a URL that expires after this many seconds. Passing it always gets you an expiring URL or an error — never a permanent link that ignores it: - On an instance that can sign ({@link SignedUrlCapability.supported}), the URL is signed, **even when a `publicBaseUrl` is configured** (a plain `url(key)` there still returns the permanent CDN link). With `signedUrl.expiry: "exact"` it expires after exactly `expiresIn`; with `"provider"` (Box, PocketBase, Dropbox temporary links) the provider sets the lifetime and `expiresIn` is advisory. - On an instance that can't sign (Vercel Blob public, UploadThing public-read, Convex, Appwrite, the filesystem, …), it throws an `Unsupported` {@link FilesError} before the adapter is called. Omit it for the adapter's default: a signed URL with its default expiry, or the permanent link when {@link AdapterCapabilities.publicUrl} is set.
numberresponseContentDisposition?string
Override the `Content-Disposition` header on the response. **Strongly recommended** for buckets that contain user-uploaded content. Without this override, the browser uses the stored Content-Type to decide whether to render or download, which means a user-uploaded `.html` (or SVG with embedded scripts) will execute inline at your bucket's origin — stored XSS in the trust context of your domain. Pass `"attachment"` (or `'attachment; filename="..."'`) to force a download. **Forces the signing path.** On signing adapters (S3, R2 HTTP, MinIO, DigitalOcean Spaces, Storj, Hetzner, Akamai, Backblaze B2, Wasabi, Tigris, R2 hybrid), passing this option always returns a presigned URL — even when `publicBaseUrl` is configured, because a permanent CDN URL has no signature in which to bind the override. If `publicBaseUrl` was the deliberate choice and you also need the security override, the override wins (it's the safe default). **Throws** on Vercel Blob (no Content-Disposition primitive) and on the R2 binding without HTTP credentials (can't sign). These cases fail loudly rather than silently dropping the security ask.
stringsignal?AbortSignal
Abort the operation when this signal is aborted. When both constructor and per-call signals are provided, either one can abort the call.
AbortSignaltimeout?number
Timeout in milliseconds, applied to each attempt (not the call as a whole). A timeout aborts the operation and is not retried. `0` or a negative value disables timeout handling.
numberretries?RetryOptions
Retry provider failures. A number is treated as `{ max: number }`.
RetryOptions