Docs / SDK reference / Storage
Storage
Server-only SDK calls — every method needs the service key. But uploads and downloads themselves go browser → R2 directly via presigned URLs. Your server hands out short-lived URLs; the browser uses them to talk to R2. Zero bytes through Flarelink or your own server.
Looking for a complete walkthrough (server route → browser upload → record key → display)? See File uploads, end to end.
Presigned upload
// SERVER — mint a URL, return it to the browser via your API
const { url, signedHeaders } = await flarelink.storage
.from("uploads")
.createSignedUploadUrl("avatars/jane.png", {
contentType: "image/png",
expiresIn: 600, // optional; default 300s, clamped to [60, 3600]
})
// BROWSER — PUT direct to R2
await fetch(url, {
method: "PUT",
headers: signedHeaders, // don't add extras — it'll break the signature
body: file, // File | Blob | ArrayBuffer
})
Send exactly signedHeaders on the PUT — adding or omitting a header (e.g. a different Content-Type) changes the SigV4 signature and R2 returns 403 SignatureDoesNotMatch.
Presigned download
const { url } = await flarelink.storage
.from("uploads")
.createSignedDownloadUrl("avatars/jane.png")
// Use it anywhere a URL works: <img src={url} />, window.open(url), fetch(url)…
Server-only operations
// Delete one or more objects (sequential under the hood)
await flarelink.storage.from("uploads").remove(["avatars/old.png"])
// List objects under a prefix (up to 1000 per call; page via cursor)
const { objects, prefixes, nextCursor } = await flarelink.storage
.from("uploads")
.list({ prefix: "avatars/" })
// All buckets on this project's R2 account
const buckets = await flarelink.storage.listBuckets()
Notes
expiresInis clamped to[60, 3600]seconds. The default is 300s — fine for an upload that starts right after the URL is minted.- The service key grants access to any bucket on the project's R2 account — it's the trust boundary, same as a raw R2 keypair. "Attach bucket" in the dashboard is organisation, not a security boundary.
- Browser uploads need the bucket's CORS to allow your app's origin. Flarelink keeps R2 CORS in sync with your auth Worker's trusted origins automatically — add an origin in the Auth panel and it propagates to attached buckets.
listreturns at most 1000 objects per call; pass the returnednextCursorback in to page.prefixesare the pseudo-folders under your prefix.- Storage failures throw
StorageError— see Error reference forR2_NOT_CONFIGURED/INVALID_SERVICE_KEYand friends.
Something unclear or missing? [email protected]
llms-full.txt ↗