Providers
All 26 storage providers — required credentials and env vars, defaults, addressing, and quirks. Three are free (S3, R2, local); the rest are Pro.
Radon Storage ships 26 providers, all built to the same completeness bar:
real API calls, signed URLs, and multipart wherever the provider supports it.
Three are free (s3, r2, local); the rest are Pro Pro
and need a license plus await storage.init().
Each adapter reads credentials from its providers config block first, then from
RADON_<SLUG>_* environment variables. Radon never stores your secrets.
Capabilities at a glance
| Provider | Tier | Public URL | Signed URL | Presigned PUT | Multipart | Copy |
|---|---|---|---|---|---|---|
| S3, R2, Backblaze, Spaces, MinIO, Wasabi, Linode, Vultr, IBM, Oracle, Scaleway, GCS | Free / Pro | Yes | Yes | Yes | Yes | Yes |
| Ceph, Storj, Filebase, Tigris, SeaweedFS | Pro | Yes | Yes | Yes | Yes | Yes |
| Alibaba OSS | Pro | Yes | Yes | Yes | Yes | Yes |
| Azure Blob | Pro | Yes | Yes | Yes | Yes | Yes |
| Supabase | Pro | Yes | Yes | Yes | No | Yes |
| Local filesystem | Free | Yes | No | No | No | Yes |
| Vercel Blob | Pro | Yes | No | No | No | No |
| UploadThing | Pro | Yes | No | Yes | No | No |
| Bunny | Pro | If publicUrl | If tokenKey | No | No | No |
| ImageKit | Pro | Yes | Yes | No | No | No |
| Cloudinary | Pro | Yes | Yes | No | No | No |
Object storage (S3-compatible)
These stores share the hand-rolled AWS SigV4 signer, verified byte-for-byte against Amazon's own published test vectors. They differ only in host, region conventions, and virtual-hosted vs. path-style addressing.
Amazon S3 (Free)
RADON_S3_ACCESS_KEY_ID=
RADON_S3_SECRET_ACCESS_KEY=
RADON_S3_BUCKET=
RADON_S3_REGION=us-east-1
# RADON_S3_ENDPOINT= # optional: S3-compatible gateway (switches to path-style)
# RADON_S3_SESSION_TOKEN= # optional: STS temporary credentialsThe reference adapter. Virtual-hosted addressing by default
(https://<bucket>.s3.<region>.amazonaws.com/<key>); region defaults to
us-east-1. Set an endpoint to use a path-style or S3-compatible gateway
instead. Supports temporary STS credentials via sessionToken.
Cloudflare R2 (Free)
RADON_R2_ACCESS_KEY_ID=
RADON_R2_SECRET_ACCESS_KEY=
RADON_R2_ACCOUNT_ID=
RADON_R2_BUCKET=
# RADON_R2_PUBLIC_URL= # optional: your r2.dev subdomain or custom domainPath-style against your account endpoint
(https://<accountId>.r2.cloudflarestorage.com/<bucket>/<key>), fixed signing
region auto. Requires an accountId (or a full endpoint).
R2 is private by default
R2 buckets have no automatic public URL. For a public getUrl(key), set
publicUrl to your r2.dev subdomain or custom domain. Otherwise use
getUrl(key, { signed: true }).
Backblaze B2 (Pro)
RADON_BACKBLAZE_ACCESS_KEY_ID=
RADON_BACKBLAZE_SECRET_ACCESS_KEY=
RADON_BACKBLAZE_BUCKET=
RADON_BACKBLAZE_REGION=us-west-004B2's S3-compatible API, virtual-hosted against the regional cluster host
(https://<bucket>.s3.<region>.backblazeb2.com). accessKeyId/secretAccessKey
are your B2 application key id and application key.
Region is required
There's no universal default cluster — you must supply your B2 region (e.g.
us-west-004) via region or RADON_BACKBLAZE_REGION, or Radon throws
InvalidConfigError.
DigitalOcean Spaces (Pro)
RADON_SPACES_ACCESS_KEY_ID=
RADON_SPACES_SECRET_ACCESS_KEY=
RADON_SPACES_BUCKET=
RADON_SPACES_REGION=nyc3Virtual-hosted against the regional endpoint
(https://<bucket>.<region>.digitaloceanspaces.com), region e.g. nyc3, ams3,
sgp1. Public objects are also served from the Spaces CDN — set publicUrl to
your <bucket>.<region>.cdn.digitaloceanspaces.com domain to use it.
MinIO (Pro)
RADON_MINIO_ACCESS_KEY_ID=
RADON_MINIO_SECRET_ACCESS_KEY=
RADON_MINIO_BUCKET=
RADON_MINIO_ENDPOINT=Self-hosted, so it requires an endpoint (your MinIO server URL) and uses
path-style addressing (<endpoint>/<bucket>/<key>). Signing region defaults
to us-east-1.
Wasabi (Pro)
RADON_WASABI_ACCESS_KEY_ID=
RADON_WASABI_SECRET_ACCESS_KEY=
RADON_WASABI_BUCKET=
RADON_WASABI_REGION=us-east-1Virtual-hosted against the regional endpoint
(https://<bucket>.s3.<region>.wasabisys.com), region defaults to us-east-1.
Linode / Akamai (Pro)
RADON_LINODE_ACCESS_KEY_ID=
RADON_LINODE_SECRET_ACCESS_KEY=
RADON_LINODE_BUCKET=
RADON_LINODE_REGION=us-east-1Virtual-hosted against the regional cluster
(https://<bucket>.<region>.linodeobjects.com), region e.g. us-east-1,
eu-central-1, ap-south-1.
Vultr Object Storage (Pro)
RADON_VULTR_ACCESS_KEY_ID=
RADON_VULTR_SECRET_ACCESS_KEY=
RADON_VULTR_BUCKET=
RADON_VULTR_REGION=ewr1Virtual-hosted against the regional host
(https://<bucket>.<region>.vultrobjects.com), region e.g. ewr1, sjc1.
Vultr signs as us-east-1
The host uses your configured region, but Vultr's SigV4 signing region is
fixed to us-east-1 regardless — Radon handles this for you.
IBM Cloud Object Storage (Pro)
RADON_IBM_ACCESS_KEY_ID=
RADON_IBM_SECRET_ACCESS_KEY=
RADON_IBM_BUCKET=
RADON_IBM_ENDPOINT=https://s3.us-south.cloud-object-storage.appdomain.cloudPath-style against a regional endpoint that varies by resiliency/region.
Requires an endpoint; uses HMAC service credentials. The signing region
is derived from the endpoint host when not set explicitly.
Oracle Cloud (Pro)
RADON_ORACLE_ACCESS_KEY_ID=
RADON_ORACLE_SECRET_ACCESS_KEY=
RADON_ORACLE_BUCKET=
RADON_ORACLE_NAMESPACE=
RADON_ORACLE_REGION=us-ashburn-1Path-style against a namespaced regional endpoint
(https://<namespace>.compat.objectstorage.<region>.oraclecloud.com).
Requires a namespace (or a full endpoint). Credentials are an OCI
Customer Secret Key.
Scaleway (Pro)
RADON_SCALEWAY_ACCESS_KEY_ID=
RADON_SCALEWAY_SECRET_ACCESS_KEY=
RADON_SCALEWAY_BUCKET=
RADON_SCALEWAY_REGION=fr-parVirtual-hosted against the regional endpoint
(https://<bucket>.s3.<region>.scw.cloud), region e.g. fr-par, nl-ams,
pl-waw.
Alibaba Cloud OSS (Pro)
RADON_ALIBABA_ACCESS_KEY_ID=
RADON_ALIBABA_SECRET_ACCESS_KEY=
RADON_ALIBABA_BUCKET=
RADON_ALIBABA_REGION=cn-hangzhouVirtual-hosted against the regional endpoint
(https://<bucket>.oss-<region>.aliyuncs.com), region e.g. cn-hangzhou (the
oss- prefix is added for you). Override the host with endpoint.
OSS uses Signature V1, not SigV4
Alibaba OSS is not AWS-SigV4-compatible, so this adapter signs with OSS's own Signature V1 scheme (HMAC-SHA1). Everything else — upload, multipart, signed URLs, copy — works through the same unified API.
Google Cloud Storage (Pro)
RADON_GCS_ACCESS_KEY_ID=
RADON_GCS_SECRET_ACCESS_KEY=
RADON_GCS_BUCKET=Uses the GCS S3-interoperable XML API with HMAC interoperability keys
(create under Cloud Storage → Settings → Interoperability). Path-style against
https://storage.googleapis.com/<bucket>, signing region auto.
Want the JSON API instead?
This adapter uses the S3-interop API with HMAC keys. For the native JSON API with
service-account/OAuth auth, drop to native() and call it via the returned
HttpClient.
Self-hosted / niche
More S3-compatible stores, all riding the same SigV4 signer.
Ceph RADOS Gateway (Pro)
RADON_CEPH_ACCESS_KEY_ID=
RADON_CEPH_SECRET_ACCESS_KEY=
RADON_CEPH_BUCKET=
RADON_CEPH_ENDPOINT=Self-hosted, so it requires an endpoint (your RGW URL) and uses
path-style addressing. The signing region is your RGW zonegroup (default
us-east-1). Credentials are the RGW user's access/secret keys.
Storj (Pro)
RADON_STORJ_ACCESS_KEY_ID=
RADON_STORJ_SECRET_ACCESS_KEY=
RADON_STORJ_BUCKET=
# RADON_STORJ_ENDPOINT= # optional: self-hosted gateway (default gateway.storjshare.io)Decentralized storage via the S3-compatible Gateway-MT. Path-style against
https://gateway.storjshare.io by default (override with endpoint), signing
region us-east-1.
Filebase (Pro)
RADON_FILEBASE_ACCESS_KEY_ID=
RADON_FILEBASE_SECRET_ACCESS_KEY=
RADON_FILEBASE_BUCKET=IPFS/Sia-backed, S3-compatible. Path-style against https://s3.filebase.com,
signing region us-east-1. Objects are pinned to IPFS behind the scenes; the
object's IPFS CID comes back in the upload response headers (surfaced in
result.raw).
Tigris (Pro)
RADON_TIGRIS_ACCESS_KEY_ID=
RADON_TIGRIS_SECRET_ACCESS_KEY=
RADON_TIGRIS_BUCKET=Globally-distributed S3-compatible store with automatic edge caching.
Path-style against https://t3.storage.dev, signing region auto. Override
the host with endpoint if needed.
SeaweedFS (Pro)
RADON_SEAWEEDFS_ACCESS_KEY_ID=
RADON_SEAWEEDFS_SECRET_ACCESS_KEY=
RADON_SEAWEEDFS_BUCKET=
RADON_SEAWEEDFS_ENDPOINT=Self-hosted via its S3 gateway (default port 8333). Requires an endpoint;
path-style; signing region defaults to us-east-1. Enable auth on the
gateway (-s3.config) to use access/secret keys.
Native-API object storage
These speak their own protocols, not S3.
Supabase Storage (Pro)
RADON_SUPABASE_URL=
RADON_SUPABASE_SERVICE_KEY=
RADON_SUPABASE_BUCKET=Talks to the Supabase Storage REST API with the project's service-role key
(no @supabase/supabase-js dependency). Public buckets get plain public URLs;
any object gets a time-limited signed URL or a signed upload URL. Uploads
overwrite by default (x-upsert).
Supabase multipart is off (TUS)
Supabase's resumable upload is TUS-based, not S3 multipart, so its multipart
capability is off. Large resumable uploads
throw UnsupportedOperationError — use a presigned upload URL
(getUrl(key, { signed: true, method: "PUT" })) for big direct uploads.
Azure Blob Storage (Pro)
RADON_AZURE_ACCOUNT=
RADON_AZURE_ACCOUNT_KEY=
RADON_AZURE_BUCKET= # container nameShared Key (HMAC-SHA256) auth over the Blob REST API (no @azure/storage-blob
dependency). bucket is your container name. Multipart is implemented via
Put Block / Put Block List; private blobs get time-limited service-SAS URLs.
Optional apiVersion (default 2021-08-06).
Azure multipart abort is a no-op
Azure chooses block ids client-side and has no "initiate multipart" call, so
createMultipartUpload() makes no network request and abortMultipartUpload()
does nothing — uncommitted blocks are auto-collected by Azure after about a week.
See Resumable uploads.
Dev / simple
Local filesystem (Free)
RADON_LOCAL_ROOT=./.radon-storage
# RADON_LOCAL_PUBLIC_URL= # optional: static host base for getUrl()Stores objects as files under a root directory — the zero-setup adapter for local
development, tests, and single-node deployments. Keys map to paths beneath the
root (traversal outside the root is refused). Supports copy, list, metadata.
No signed URLs on the filesystem
The local adapter has no signing (signedUrls: false) and no multipart.
getUrl(key, { signed: true }) throws. getUrl(key) returns a file:// URL, or
an HTTP URL under publicUrl if you serve the root with a static file server.
Vercel Blob (Pro)
RADON_VERCEL_BLOB_TOKEN= # your BLOB_READ_WRITE_TOKENVercel's public-by-default blob store, via the Blob HTTP API with a Bearer token. Every blob gets a public CDN URL on upload.
Public URLs only — no signing, no copy
Vercel Blob has no private/signed URLs (getUrl({ signed: true }) throws), no
server-side copy, and no multipart. Because blob URLs embed a random store id,
delete/getMetadata/getUrl resolve a key to its full URL via a prefix list
first. Use the public URL from upload().
UploadThing (Pro)
RADON_UPLOADTHING_API_KEY= # your sk_... secretPresents the unified surface over UploadThing's server REST API (the "UTApi").
Uploads are a two-step register → PUT handshake, so presignedUpload is
true; files are served from a public CDN (utfs.io / your *.ufs.sh). Objects
are keyed by the name/customId you upload and resolved back via listFiles.
Public CDN only
UploadThing has no signed URLs (getUrl({ signed: true }) throws), no S3
multipart, and no server-side copy.
CDN / media-focused
Bunny.net Edge Storage (Pro)
RADON_BUNNY_BUCKET= # storage zone name
RADON_BUNNY_ACCESS_KEY= # storage zone password
RADON_BUNNY_PUBLIC_URL= # your pull-zone hostname, e.g. https://cdn.b-cdn.net
# RADON_BUNNY_REGION=ny # optional: storage region prefix (default main region)
# RADON_BUNNY_TOKEN_KEY= # optional: pull-zone token key (enables signed URLs)A simple AccessKey-header REST API over your storage zone (bucket = storage
zone name, accessKey = its password). Public delivery is via a linked pull
zone. No server-side multipart or copy — large files stream through a single PUT.
URLs need publicUrl, signing needs tokenKey too
Bunny builds object URLs only when publicUrl is set (otherwise getUrl()
throws). Signed URLs additionally require tokenKey (your pull-zone
token-authentication key); without it, getUrl({ signed: true }) throws.
ImageKit (Pro)
RADON_IMAGEKIT_PRIVATE_KEY=
RADON_IMAGEKIT_URL_ENDPOINT= # e.g. https://ik.imagekit.io/your_idMedia storage plus a real-time image/video CDN. Uploads go through the multipart
form upload endpoint (Basic auth with the private key); management uses the
REST API. Private files get time-limited signed URLs (ik-t/ik-s, HMAC-SHA1).
No S3 multipart or server-side copy. A key is resolved to ImageKit's internal
fileId via search for delete/details.
Cloudinary (Pro)
RADON_CLOUDINARY_CLOUD_NAME=
RADON_CLOUDINARY_API_KEY=
RADON_CLOUDINARY_API_SECRET=
# resourceType option: image | video | raw | auto (default image)Media storage plus a transformation CDN. Uploads are signed multipart POSTs;
management uses the Admin API. Private assets get signed delivery URLs
(s--<sig>--). No S3 multipart or server-side copy.
Keys map to Cloudinary public_ids
A key maps to Cloudinary's public_id, and public_ids conventionally omit
the file extension — Radon strips it for you. Set resourceType (image,
video, raw, or auto) to match the asset kind; it defaults to image.
A few adapters carry VERIFY-vs-live flags
Azure, Alibaba OSS, Vercel Blob, and UploadThing have a handful of wire details (version-dependent signing fields, evolving APIs) that were implemented to spec but flagged for confirmation against a live account before production. The whole SigV4 S3 family is verified against Amazon's published test vectors.
Listing & metadata
Enumerate objects with list() — prefixes, pagination via cursor and hasMore, delimiter "folders" — plus getMetadata() and exists() for inspecting single objects.
API reference
Every public method of RadonStorage, its options and return type, plus configuration, upload input, URL options, list options, and the result shapes — exhaustively.