Radon/SDKs/Storage
@radonsdk/storage26 providers

One upload() across 26 stores.

Object storage, CDN/media, self-hosted, and local — S3, R2, GCS, Azure, Supabase, Cloudinary, and more. Signed URLs, resumable uploads, and multi-provider failover, with every wire protocol hand-rolled so there are zero dependencies.

$npm i @radonsdk/storage
storage.ts
import { RadonStorage } from "@radonsdk/storage";

const storage = new RadonStorage({
  providers: { s3: { bucket: "uploads", region: "us-east-1" } },
  defaultProvider: "s3",
});

const { url } = await storage.upload({
  key: "avatars/ada.png",
  path: "./ada.png",
});
01what you get
01

26 providers

The whole S3-compatible family plus GCS, Azure Blob, Supabase, Bunny, ImageKit, Cloudinary, and self-hosted MinIO/Ceph/SeaweedFS.

02

Upload anything

Bytes, a stream, text, or a file path — the same upload({ key }) call, with content-type inferred for you.

03

Signed URLs

Time-limited links for private objects, signed with SigV4 — getUrl(key, { signed: true, expiresIn }).

04

Resumable & multipart

Chunked, resumable uploads (8 MiB parts) across the S3 family and Azure — for large files that must survive a dropped connection.

05

Multi-provider failover

Declare a chain — try S3, fall back to R2 — and writes automatically retry the next provider on failure.

06

Native escape hatch

storage.native() hands you the provider's own client for anything the unified API doesn't cover.

02providers

3 free, 23 on Pro — same call for every one.

3 freeproduction-grade, no license
Amazon S3Amazon S3Cloudflare R2Cloudflare R2LocalLocal
23 Proone key unlocks all
SupabaseSupabaseBackblaze B2Backblaze B2DigitalOcean SpacesDigitalOcean SpacesMinIOMinIOWasabiWasabiLinodeLinodeVultrVultrIBM COSIBM COSOracle CloudOracle CloudScalewayScalewayAlibaba OSSAlibaba OSSCephCephStorjStorjFilebaseFilebaseTigrisTigrisSeaweedFSSeaweedFSGoogle Cloud StorageGoogle Cloud StorageAzure BlobAzure BlobVercel BlobVercel BlobUploadThingUploadThingBunnyBunnyImageKitImageKitCloudinaryCloudinary
03the API

A small, typed surface.

  • storage.upload({ key, path }): Promise<UploadResult>

    Upload from a path, Buffer, stream, or string; returns key + url.

  • storage.getUrl(key, { signed, expiresIn }): Promise<string>

    A public or time-limited signed URL for an object.

  • storage.download(key): Promise<Buffer>

    Read an object back into memory.

  • storage.list(prefix): Promise<ListResult>

    List objects and common prefixes, with cursor pagination.

  • storage.uploadResumable(input): Promise<UploadResult>PRO

    Chunked, resumable upload for large files.

  • storage.delete(key) · exists(key) · copy(src, dst)

    The rest of the object lifecycle, uniform across providers.

04A time-limited link
storage-example.ts
// A private invoice, shareable for one hour:
const link = await storage.getUrl("invoices/2026-01.pdf", {
  signed: true,
  expiresIn: 3600,
});

getUrl and list don't fail over

Reads through the failover chain (upload, download, delete) retry the next provider — but getUrl and list always use the primary. Also: Cloudflare R2 is private by default, so set publicUrl or use signed URLs.