Store and retrieve files
Blossom is an HTTP file server protocol. It is a separate service alongside the Nostr relays. Select a server origin explicitly:
const files = db.storage.from("https://files.example.com");
const uploaded = await files.upload("images/avatar.png", imageBlob);
if (uploaded.error) throw uploaded.error;
const { sha256, url } = uploaded.data!;
const downloaded = await files.download(sha256);
const page = await files.list(undefined, { limit: 20 });
const removed = await files.remove([sha256]);
The name is display metadata. File objects use their SHA-256 hash as the key. File names do not create folders or affect addressing. Publish the returned descriptor or reference in a Nostr record to associate it with your app.
The implementation follows BUD-01 retrieval, BUD-02 upload, BUD-11 authorization, and BUD-12 management:
- Upload:
PUT /uploadwith raw bytes, MIME type, andX-SHA-256. - Download:
GET /<sha256>, followed by a local hash check. - Remove: separate
DELETE /<sha256>requests with per-object success or error results. - List:
GET /list/<pubkey>with optionalcursorandlimit. Some servers do not implement list. - Authorization: signed kind
24242events, short expiry, server hostname scope, and hash scope for upload, download authorization, and deletion.
Uploads, deletion, and listing request the active signer’s approval. Public downloads work without a signer. Use download(hash, { authenticated: true }) for a server that requires a scoped get token.
Upload descriptors must match the uploaded hash and byte count. Downloads must match the requested hash. Requests always use the chosen server; the SDK does not send uploads or authorization tokens to descriptor URLs. HTTP redirects are rejected. Use the final file server origin when a provider uses redirects. Servers can return public CDN URLs in validated descriptors, which your app may use separately.
Cancellation and request timeout:
const controller = new AbortController();
await files.upload("notes.txt", blob, { signal: controller.signal, timeout: 15_000 });
Configure a custom fetch implementation and the default storage request timeout on the client:
const db = createClient({
namespace: "my-app",
relays: ["wss://relay.example.com"],
signer,
storage: { fetch: customFetch, timeout: 15_000 },
});
File bytes are public unless your app encrypts them before upload. Server storage limits, retention, payments, and upload permissions follow the selected server’s policy. Private table encryption does not encrypt file bytes automatically.