Radondocs

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

ProviderTierPublic URLSigned URLPresigned PUTMultipartCopy
S3, R2, Backblaze, Spaces, MinIO, Wasabi, Linode, Vultr, IBM, Oracle, Scaleway, GCSFree / ProYesYesYesYesYes
Ceph, Storj, Filebase, Tigris, SeaweedFSProYesYesYesYesYes
Alibaba OSSProYesYesYesYesYes
Azure BlobProYesYesYesYesYes
SupabaseProYesYesYesNoYes
Local filesystemFreeYesNoNoNoYes
Vercel BlobProYesNoNoNoNo
UploadThingProYesNoYesNoNo
BunnyProIf publicUrlIf tokenKeyNoNoNo
ImageKitProYesYesNoNoNo
CloudinaryProYesYesNoNoNo

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)

.env
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 credentials

The 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)

.env
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 domain

Path-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)

.env
RADON_BACKBLAZE_ACCESS_KEY_ID=
RADON_BACKBLAZE_SECRET_ACCESS_KEY=
RADON_BACKBLAZE_BUCKET=
RADON_BACKBLAZE_REGION=us-west-004

B2'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)

.env
RADON_SPACES_ACCESS_KEY_ID=
RADON_SPACES_SECRET_ACCESS_KEY=
RADON_SPACES_BUCKET=
RADON_SPACES_REGION=nyc3

Virtual-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)

.env
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)

.env
RADON_WASABI_ACCESS_KEY_ID=
RADON_WASABI_SECRET_ACCESS_KEY=
RADON_WASABI_BUCKET=
RADON_WASABI_REGION=us-east-1

Virtual-hosted against the regional endpoint (https://<bucket>.s3.<region>.wasabisys.com), region defaults to us-east-1.

Linode / Akamai (Pro)

.env
RADON_LINODE_ACCESS_KEY_ID=
RADON_LINODE_SECRET_ACCESS_KEY=
RADON_LINODE_BUCKET=
RADON_LINODE_REGION=us-east-1

Virtual-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)

.env
RADON_VULTR_ACCESS_KEY_ID=
RADON_VULTR_SECRET_ACCESS_KEY=
RADON_VULTR_BUCKET=
RADON_VULTR_REGION=ewr1

Virtual-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)

.env
RADON_IBM_ACCESS_KEY_ID=
RADON_IBM_SECRET_ACCESS_KEY=
RADON_IBM_BUCKET=
RADON_IBM_ENDPOINT=https://s3.us-south.cloud-object-storage.appdomain.cloud

Path-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)

.env
RADON_ORACLE_ACCESS_KEY_ID=
RADON_ORACLE_SECRET_ACCESS_KEY=
RADON_ORACLE_BUCKET=
RADON_ORACLE_NAMESPACE=
RADON_ORACLE_REGION=us-ashburn-1

Path-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)

.env
RADON_SCALEWAY_ACCESS_KEY_ID=
RADON_SCALEWAY_SECRET_ACCESS_KEY=
RADON_SCALEWAY_BUCKET=
RADON_SCALEWAY_REGION=fr-par

Virtual-hosted against the regional endpoint (https://<bucket>.s3.<region>.scw.cloud), region e.g. fr-par, nl-ams, pl-waw.

Alibaba Cloud OSS (Pro)

.env
RADON_ALIBABA_ACCESS_KEY_ID=
RADON_ALIBABA_SECRET_ACCESS_KEY=
RADON_ALIBABA_BUCKET=
RADON_ALIBABA_REGION=cn-hangzhou

Virtual-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)

.env
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)

.env
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)

.env
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)

.env
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)

.env
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)

.env
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)

.env
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)

.env
RADON_AZURE_ACCOUNT=
RADON_AZURE_ACCOUNT_KEY=
RADON_AZURE_BUCKET=          # container name

Shared 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)

.env
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)

.env
RADON_VERCEL_BLOB_TOKEN=    # your BLOB_READ_WRITE_TOKEN

Vercel'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)

.env
RADON_UPLOADTHING_API_KEY=  # your sk_... secret

Presents 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)

.env
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)

.env
RADON_IMAGEKIT_PRIVATE_KEY=
RADON_IMAGEKIT_URL_ENDPOINT=   # e.g. https://ik.imagekit.io/your_id

Media 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)

.env
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.

On this page