Using the Blob SDK

Learn how to use the hub:blob SDK to list, read, store, and delete files in your Blob Storage.

The hub:blob module provides access to Blob Storage through a unified SDK that works across all storage providers (Cloudflare R2, S3, Vercel Blob, filesystem).

import { blob } from 'hub:blob'
blob is auto-imported on server-side, you can directly use it without importing it from hub:blob.

List blobs

This example create an API route to list the first 10 blobs in the Blob storage.

server/api/files.get.ts
export default eventHandler(async () => {
  const { blobs } = await blob.list({ limit: 10 })

  return blobs
})

list()

Returns a paginated list of blobs (metadata only).

await blob.list(options)
When using the local filesystem driver, the limit option is ignored and all blobs are returned.

Params

options
Object
The list options.

Return

Returns a json object with the following structure:

{
  blobs:  {
    pathname: string
    contentType: string | undefined
    size: number
    httpEtag: string | undefined
    uploadedAt: Date
    httpMetadata: Record<string, string>
    customMetadata: Record<string, string>
    url?: string
  }[]
  hasMore: boolean
  cursor?: string
  folders?: string[]
}

List with prefix

Filter blobs by a prefix to organize files into directories:

// List all files in the "images/" directory
const { blobs } = await blob.list({ prefix: 'images/' })

List with folders

Use folded: true to get a folder-like structure:

const { blobs, folders } = await blob.list({ folded: true })

// folders: ['images/', 'documents/', 'videos/']

Pagination

Fetch all blobs using cursor-based pagination:

let allBlobs = []
let cursor = null

do {
  const result = await blob.list({ cursor })
  allBlobs.push(...result.blobs)
  cursor = result.cursor
} while (cursor)

Serve a blob

This example create a server route on /images/[...pathname] to serve a blob by its pathname.

server/routes/images/[...pathname].get.ts
export default eventHandler(async (event) => {
  const { pathname } = getRouterParams(event)

  return blob.serve(event, pathname)
})

To display the image in your application, you can use the <img> tag with the pathname of the blob.

pages/index.vue
<template>
  <img src="/images/my-image.jpg">
</template>
To prevent XSS attacks, make sure to control the Content type of the blob you serve.

You can also set a Content-Security-Policy header for additional security:

server/routes/images/[...pathname].get.ts
export default eventHandler(async (event) => {
  const { pathname } = getRouterParams(event)

  setHeader(event, 'Content-Security-Policy', 'default-src \'none\';')
  return blob.serve(event, pathname)
})

serve()

Returns a blob's data and sets Content-Type, Content-Length, and ETag headers.

await blob.serve(event, 'images/my-image.jpg')

Params

event
H3Event required
Handler's event, needed to set headers.
pathname
String required
The pathname of the blob to serve.

Return

Returns the blob's raw data and sets Content-Type, Content-Length, and ETag headers.

Get blob metadata

This example create an API route to get a blob's metadata by its pathname.

server/api/files/[...pathname].get.ts
import { blob } from 'hub:blob'
import { eventHandler, getRouterParams } from 'h3'

export default eventHandler(async (event) => {
  const { pathname } = getRouterParams(event)

  return blob.head(pathname)
})

Returns a blob's metadata without fetching the content.

await blob.head('images/avatar.png')
// { pathname, contentType, size, uploadedAt, ... }

Params

pathname
String required
The pathname of the blob.

Return

Returns a json object with the following structure:

{
  pathname: string
  contentType: string | undefined
  size: number
  httpEtag: string | undefined
  uploadedAt: Date
  httpMetadata: Record<string, string>
  customMetadata: Record<string, string>
  url?: string
}

Get blob body

This example show a server code to get a blob's content by its pathname, and convert it to a text or buffer.

const file = await blob.get('documents/report.pdf')

if (file) {
  const text = await file.text()
  // or: const buffer = await file.arrayBuffer()
}

get()

Returns a blob's content as a Blob object.

const file = await blob.get('documents/report.pdf')

Params

pathname
String required
The pathname of the blob.

Return

Returns a Blob or null if not found.

Upload a blob

This example create an API route to upload an image of 1MB maximum to the Blob storage.

server/api/files.post.ts
import { ensureBlob, blob } from 'hub:blob'
import { eventHandler, readFormData, createError } from 'h3'

export default eventHandler(async (event) => {
  const form = await readFormData(event)
  const file = form.get('file') as File

  if (!file || !file.size) {
    throw createError({ statusCode: 400, message: 'No file provided' })
  }

  ensureBlob(file, {
    maxSize: '1MB',
    types: ['image'],
  })

  return blob.put(file.name, file, {
    addRandomSuffix: false,
    prefix: 'images',
  })
})
For a higher-level upload API with validation and client composables, see the File Uploads guide.

put()

await blob.put('images/1.jpg', file)

await blob.put(file.name, file, {
  access: 'public',
  addRandomSuffix: true,
  prefix: 'images/',
  customMetadata: {
    userId: '123',
    category: 'reports',
  },
})

Params

pathname
String required
The pathname for the blob.
body
string | ReadableStream | ArrayBuffer | ArrayBufferView | Blob required
The blob's data.
options
Object
The put options. Any other provided field will be stored in the blob's metadata.

Return

Returns a json object with the following structure:

{
  pathname: string
  contentType: string | undefined
  size: number
  httpEtag: string | undefined
  uploadedAt: Date
  httpMetadata: Record<string, string>
  customMetadata: Record<string, string>
  url?: string
}

Upload Examples

Upload from a URL:

const response = await fetch('https://example.com/image.png')
const imageBlob = await response.blob()

await blob.put('downloads/image.png', imageBlob)

Upload with custom metadata:

await blob.put('documents/report.pdf', pdfFile, {
  customMetadata: {
    userId: '123',
    category: 'reports',
  },
})

Upload to a specific folder:

await blob.put('avatar.png', file, {
  prefix: `users/${userId}`,
})
// Stored as: users/123/avatar.png

Deleting blobs

To delete a file, you can use the blob.del() method.

This example create an API route to delete a blob by its pathname.

server/api/files/[...pathname].delete.ts
import { blob } from 'hub:blob'
import { eventHandler, getRouterParams, sendNoContent } from 'h3'

export default eventHandler(async (event) => {
  const { pathname } = getRouterParams(event)

  await blob.del(pathname)

  return sendNoContent(event)
})

del()

The del() method deletes one or multiple blob objects from the Blob storage.

You can also delete multiple blobs at once:

await blob.del('images/1.jpg')
await blob.del(['images/1.jpg', 'images/2.jpg', 'images/3.jpg'])
You can also use delete() as an alias for del().

Params

pathname
String | String[] required
The pathname(s) of the blob(s) to delete.

Return

Returns nothing.

Validation

ensureBlob()

A server-side utility to validate a file by checking its size and type before uploading.

import { ensureBlob } from 'hub:blob'

// Will throw an error if the file is not an image or is larger than 1MB
ensureBlob(file, { maxSize: '1MB', types: ['image'] })
This utility is automatically used by handleUpload() when you provide the ensure option.

Params

file
Blob required
The file to validate.
options
Object required
Note that at least maxSize or types should be provided.

Return

Returns nothing. Throws an error if the file doesn't meet the requirements.