Quickstart
Store your first file with Radon Storage in about five minutes — upload it, get a signed URL, and read it back. One provider, no branching decisions.
By the end of this page you'll have uploaded a file, minted a signed URL, and downloaded the bytes back — all through Radon's unified API. We'll use Amazon S3 because it's free (no license) and its credentials are quick to create, but every step maps onto any of the 26 providers.
Prerequisites
Node 18 or newer, and an AWS account with an S3 bucket plus an access key
(AKIA…) and secret from the
IAM console.
Install the package
npm i @radonsdk/storageZero required dependencies — no @aws-sdk/*, no axios. Radon talks to every
provider over fetch.
Set your credentials
Radon reads provider credentials from environment variables named
RADON_<PROVIDER>_<KEY>, so you never hard-code secrets. For S3:
RADON_S3_ACCESS_KEY_ID=AKIA...
RADON_S3_SECRET_ACCESS_KEY=...
RADON_S3_BUCKET=my-uploads
RADON_S3_REGION=us-east-1Create the client
import { RadonStorage } from "@radonsdk/storage";
export const storage = new RadonStorage({
providers: { s3: {} }, // {} = read everything from RADON_S3_*
defaultProvider: "s3",
});With free-only providers (s3, r2, local) you don't need to call
storage.init(). init() is only required when you configure a Pro provider,
or use a Pro feature like resumable upload or failover — it verifies your
license.
Upload a file
Provide a destination key and either body (bytes, a stream, or text) or a
local path. The content type is inferred from the key's extension when you
don't pass one.
import { storage } from "@/lib/storage";
const result = await storage.upload({
key: "avatars/ada.png",
path: "./ada.png",
});
console.log(result.key); // "avatars/ada.png"
console.log(result.provider); // "s3"
console.log(result.size); // bytes stored
console.log(result.etag); // the entity tag S3 assignedYou should see the object appear in your S3 bucket under
avatars/ada.png, andresult.sizematch the file on disk.
Get a signed URL
S3 objects are private by default. A signed URL grants time-limited read access without making the object public — perfect for handing a download link to a browser.
const url = await storage.getUrl("avatars/ada.png", {
signed: true,
expiresIn: 3600, // seconds — 1 hour (the default)
});
// https://my-uploads.s3.us-east-1.amazonaws.com/avatars/ada.png?X-Amz-Algorithm=...Anyone with this URL can GET the object until it expires. See
Signed URLs for presigned uploads and per-provider
support.
Read it back
download() pulls the object's bytes into a Buffer.
const bytes = await storage.download("avatars/ada.png");
console.log(bytes.length); // same size you uploaded
// Confirm it's there, and inspect it, without downloading:
await storage.exists("avatars/ada.png"); // true
await storage.getMetadata("avatars/ada.png"); // { size, contentType, lastModified, ... }🎉 That's it
You stored a file, signed a URL, and read it back through a unified API. The
exact same code runs on R2, Supabase, Azure Blob, or Cloudinary — you'd only
change the providers config.
Next steps
Radon Storage
One unified, provider-agnostic API for 26 file-storage providers — object storage, CDN/media, self-hosted, and dev/local. Write storage.upload() once and swap providers with a config change, never a code change.
Core concepts
The mental model behind Radon Storage — providers, the storage contract, keys, capabilities, signed URLs, test vs live, and the native() escape hatch.