Store a blob
Write request bodies and uploaded files to Blob storage from Vite or Nitro routes.
This guide focuses on the write path. It assumes Blob is already registered.
Write Pattern
Every write route follows the same shape:
- Read a request body or uploaded file.
- Validate the input when it comes from a user.
- Pick a pathname.
- Call
blob.put(pathname, body, options). - Return the stored metadata.
Store JSON Body Content
server/api/notes.put.ts
import { defineEventHandler, readBody } from 'h3'
import { blob } from '@vitehub/blob'
export default defineEventHandler(async (event) => {
const body = await readBody<{ pathname?: string, text?: string }>(event)
return await blob.put(
body.pathname || 'notes/example.txt',
body.text || '',
{ contentType: 'text/plain; charset=utf-8' },
)
})
Store an Uploaded File
Use readFormData() for multipart uploads and validate the Blob before writing it.
import { createError, defineEventHandler, readFormData } from 'h3'
import { blob, ensureBlob } from '@vitehub/blob'
export default defineEventHandler(async (event) => {
const form = await readFormData(event)
const file = form.get('file')
if (!(file instanceof Blob)) {
throw createError({ statusCode: 400, statusMessage: 'Expected a file upload.' })
}
ensureBlob(file, {
maxSize: '1MB',
types: ['image'],
})
return await blob.put('avatar.png', file, {
addRandomSuffix: true,
prefix: 'avatars',
})
})
Add Metadata
Use customMetadata for small provider metadata attached to the object.
const stored = await blob.put('avatars/user-1.png', file, {
contentType: file.type,
customMetadata: {
owner: 'user-1',
source: 'profile-form',
},
})
Use Prefixes and Random Suffixes
prefix is prepended before storage. addRandomSuffix changes the final filename.
const stored = await blob.put('avatar.png', file, {
addRandomSuffix: true,
prefix: 'avatars/user-1',
})
return {
pathname: stored.pathname,
}
Example final pathname:
avatars/user-1/avatar-a1b2c3d4.png
Verify the Write
curl -X PUT http://localhost:3000/api/notes \
-H 'content-type: application/json' \
-d '{"pathname":"notes/example.txt","text":"hello world"}'
Expected response:
{
"pathname": "notes/example.txt",
"contentType": "text/plain; charset=utf-8",
"size": 11
}
Avoid These Mistakes
| Mistake | Fix |
|---|---|
Ignoring the returned pathname after using addRandomSuffix | Store or return stored.pathname. |
| Trusting client-provided content type without validation | Use ensureBlob() before blob.put(). |
| Putting provider tokens in route code | Put tokens, bindings, and bucket names in config or environment. |

