File uploads
ViteHub Blob supports upload workflows from validated form uploads to large multipart uploads.
Simple upload
For most use cases, use blob.handleUpload() in a route that receives FormData.
import { defineEventHandler } from 'h3'
import { blob } from '@vitehub/blob'
export default defineEventHandler(async (event) => {
return await blob.handleUpload(event, {
formKey: 'files',
multiple: true,
ensure: {
maxSize: '10MB',
types: ['image/jpeg', 'image/png', 'image/webp'],
},
put: {
addRandomSuffix: true,
prefix: 'images',
},
})
})
handleUpload()
blob.handleUpload() validates uploaded files and stores them with blob.put().
await blob.handleUpload(event, options)
Parameters
files.true.ensureBlob().blob.put().Return value
Returns an array of BlobObject items. When multiple is false, the array contains a single uploaded blob.
Full example
import { defineEventHandler } from 'h3'
import { blob } from '@vitehub/blob'
export default defineEventHandler(async (event) => {
return await blob.handleUpload(event, {
formKey: 'files',
multiple: true,
ensure: {
maxSize: '10MB',
types: ['image'],
},
put: {
addRandomSuffix: true,
prefix: 'avatars',
},
})
})
Multipart upload
For large files, expose blob.handleMultipartUpload() on a dedicated route and drive the upload flow from your app or service code.
import { defineEventHandler } from 'h3'
import { blob } from '@vitehub/blob'
export default defineEventHandler(async (event) => {
return await blob.handleMultipartUpload(event, {
addRandomSuffix: true,
prefix: 'uploads',
})
})
import { defineEventHandler } from 'h3'
import { blob } from '@vitehub/blob'
export default defineEventHandler(async (event) => {
return await blob.handleMultipartUpload(event, {
addRandomSuffix: true,
prefix: 'uploads',
})
})
handleMultipartUpload()
blob.handleMultipartUpload() handles multipart upload lifecycle actions:
createuploadcompleteabort
await blob.handleMultipartUpload(event, options)
Parameters
Return value
The route returns the multipart payload for the current action:
create:{ pathname, uploadId }upload:{ partNumber, etag }complete:BlobObjectabort: no content
useMultipartUpload()
Use the client helper from @vitehub/blob/client to drive multipart uploads from a Nuxt app or any Vue client that can reach your Nitro routes.
<script setup lang="ts">
import { useMultipartUpload } from '@vitehub/blob/client'
const uploader = useMultipartUpload('/api/files/multipart', {
partSize: 10 * 1024 * 1024,
concurrent: 3,
})
const file = ref<File | null>(null)
const progress = ref(0)
const uploading = ref(false)
let abortUpload: null | (() => Promise<void>) = null
async function startUpload() {
if (!file.value)
return
uploading.value = true
const { completed, progress: uploadProgress, abort } = uploader(file.value)
abortUpload = abort
watch(uploadProgress, (value) => {
progress.value = value
}, { immediate: true })
try {
await completed
}
finally {
uploading.value = false
abortUpload = null
}
}
</script>
Parameters
10MB.1.3.Return value
Returns a function that accepts a File and returns:
{
completed: Promise<BlobObject | undefined>
progress: Readonly<Ref<number>>
abort: () => Promise<void>
}
blobProvider: 'vercel-blob', useMultipartUpload() switches to the Vercel Blob client upload flow automatically.Manual multipart flow
You can still use the lower-level blob SDK directly when you need custom upload behavior.
const multipart = await blob.createMultipartUpload('videos/demo.mp4', {
contentType: 'video/mp4',
prefix: 'videos',
})
await multipart.uploadPart(1, chunk1)
await multipart.uploadPart(2, chunk2)
await multipart.complete([
{ partNumber: 1, etag: 'etag-1' },
{ partNumber: 2, etag: 'etag-2' },
])