Supabase Storage
Supabase Storage via @supabase/storage-js. Pass an existing SupabaseClient to share auth/postgrest with the rest of your app.
Installation
@supabase/storage-js is an optional peer dependency of files-sdk - install alongside the SDK so the adapter’s imports resolve at runtime.
npm install files-sdk @supabase/storage-jspnpm add files-sdk @supabase/storage-jsyarn add files-sdk @supabase/storage-jsbun add files-sdk @supabase/storage-jsUsage
Supabase Storage via the official @supabase/storage-js SDK. Auto-loads the project URL and an API key from the standard env vars; pass client to share an existing SupabaseClient with the rest of your app (auth, postgrest).
import { Files } from "files-sdk";
import { supabase } from "files-sdk/supabase";
const files = new Files({
adapter: supabase({
bucket: "uploads",
// Auto-loads url + key from SUPABASE_URL / NEXT_PUBLIC_SUPABASE_URL
// and SUPABASE_SERVICE_ROLE_KEY / SUPABASE_KEY /
// NEXT_PUBLIC_SUPABASE_ANON_KEY. Or pass an existing SupabaseClient
// via `client` to share with auth/postgrest.
}),
});
Options
bucketstring
Supabase storage bucket. Must already exist (this SDK does not create buckets). Surfaced as `bucket` on the returned adapter for cross-adapter API consistency (S3/R2/GCS/MinIO/Azure all expose `bucket`).
stringclient?StorageClient | { storage: StorageClient }
Existing client instance. Highest precedence. Pass either: - a `StorageClient` (from `@supabase/storage-js`), or - a `SupabaseClient` (from `@supabase/supabase-js`) — the adapter will pick `client.storage` automatically. Useful when the consumer already constructs a Supabase client for auth or postgrest and wants to share it with the storage adapter.
StorageClient | { storage: StorageClient }url?string
Supabase project URL (e.g. `https://xxxx.supabase.co`). Required if `client` is not provided. The adapter appends `/storage/v1` automatically when constructing a `StorageClient`. Falls back to `SUPABASE_URL`, then `NEXT_PUBLIC_SUPABASE_URL`.
stringkey?string
Supabase API key. The service role key is required for write operations on RLS-protected buckets; the anon key works for public buckets. Falls back to `SUPABASE_SERVICE_ROLE_KEY`, then `SUPABASE_KEY`, then `NEXT_PUBLIC_SUPABASE_ANON_KEY`.
stringpublic?boolean
Set to `true` if the bucket is configured as a public bucket. `url()` will then return `getPublicUrl()` results — a permanent, unsigned URL — instead of minting a signed read URL. Supabase exposes no API to detect bucket visibility from the client; if `public: true` is set on a private bucket, the returned URL will 4xx when fetched.
booleanpublicBaseUrl?string
Origin used to build URLs from `url()`. When set, `url(key)` returns `${publicBaseUrl}/${key}` and skips both signing and `getPublicUrl()` — appropriate when a CDN sits in front of the Supabase project. Implies `public: true`.
stringdefaultUrlExpiresIn?number
Default expiry, in seconds, for the signed read URLs returned by `url()` when neither `public` nor `publicBaseUrl` is set. Defaults to 3600 (1 hour). Per-call `url(key, { expiresIn })` overrides.
numberCompatibility
| Method | Status | Notes |
|---|---|---|
upload |
✅ | |
download |
✅ | |
delete |
✅ | |
list |
✅ | Uses Supabase’s V2 list API: a flat, recursive, string-prefix scan over full keys with a real server cursor. (The legacy V1 API is folder-scoped and non-recursive, so it could not back the unified list contract.) |
search |
⚠️ | Built on listAll — inherits this adapter’s list behavior above. Client-side key match (glob, regex, substring, exact). |
head |
✅ | |
exists |
✅ | |
copy |
✅ | |
url |
⚠️ | Default mints a signed read URL via createSignedUrl (1-hour default). With public: true, returns the permanent unsigned getPublicUrl result. With publicBaseUrl, returns <publicBaseUrl>/<key>. responseContentDisposition is honored - it threads through Supabase’s download option in the signed path. |
signedUploadUrl |
⚠️ | PUT URL only - Supabase has no POST policy equivalent. maxSize throws (Supabase signed upload URLs have no content-length-range policy; set the bucket-level size limit in the dashboard instead). expiresIn is silently ignored - Supabase fixes the TTL at 2 hours server-side. The returned headers include x-upsert: true. |