Ferrite Object Storage keeps large values outside small Store records. Objects are content-addressed and verified when read, making corruption and accidental replacement visible.
Store an object
let mut uploads = ctx.blob("uploads")?;
uploads.put(b"tenant/acme/evidence/report.pdf", &bytes).await?;
let report = uploads.get(b"tenant/acme/evidence/report.pdf").await?;
Use tenant-scoped logical keys even though the storage layer verifies content. Store metadata, ownership, retention, and authorization state in Store; keep the bytes in Object Storage.
Serve static content
Map a content route to a blob binding and key prefix:
{
"services": [{ "name": "site-assets", "primitive": "blob" }],
"applications": [{
"name": "site",
"artifact_key": "apps/site@v1",
"artifact_sha256": "0000000000000000000000000000000000000000000000000000000000000000",
"bindings": [
{ "handle": "web-assets", "kind": "blob", "service": "site-assets" }
],
"routes": [{
"prefix": "/",
"binding": "web-assets",
"kind": "content",
"key_prefix": "site/",
"public": true
}]
}]
}
This developer portal uses the same pattern: Astro produces static assets, a Ferrite function uploads them to its scoped blob space, and the Gateway serves them with the correct route policy.
Sensitive content
Do not mark a content route public when object access depends on a user or tenant. Use an authenticated API that checks authorization before reading the scoped object and returning its bytes.
See Authorization and Headers & Cookies.