Uploading images and files
Bytes to Blob, metadata to Postgres, and an asset id derived from the bytes — so uploading the same file twice stores it once.
An upload does three things: it stores the bytes, it writes an asset document, and it returns a reference the schema can hold.
const asset = await client.assets.upload('image', file, {
filename: 'cover.png',
title: 'Cover',
})
await client.patch('post-1').set({
coverImage: {
_type: 'image',
asset: { _type: 'reference', _ref: asset._id },
alt: 'Required by this schema',
},
}).commit()The id is the bytes
An asset id has the form image-<hash>-<width>x<height>-<ext>, derived from a hash of the content. Two consequences follow, and both are useful:
- Uploading the same file twice stores it once. The second upload is a metadata write, and the byte store is not touched.
- Ids are stable across deployments. The demo images in this repository produce the same asset ids in every deployment of it, which is what makes re-seeding a byte-level no-op.
Two upload paths
| Path | When | Limit |
|---|---|---|
| Server-receive | The default, for ordinary images | About 4.5 MB, the serverless request body ceiling |
| Browser-direct | Anything larger | The Blob store's own limits |
The direct path issues a short-lived token, the browser uploads straight to storage, and the API then commits the metadata document. The Studio picks the right path itself.
Deleting
Deleting an asset orphan-marks the row and retains the bytes, so a daily job can reclaim them. That is deliberate: an asset referenced by an old revision is not garbage merely because the current document stopped pointing at it.
