Setup

Configure Blob Storage in your Nuxt application, including installation, environment variables, and initial setup for uploading and serving files.

Getting Started

Enable blob storage in your project by setting blob: true in the NuxtHub config.

nuxt.config.ts
export default defineNuxtConfig({
  hub: {
    blob: true
  }
})

Automatic Configuration

NuxtHub automatically configures the blob storage driver based on your hosting provider when blob: true is set in the NuxtHub config.

When deploying to Vercel, it automatically configures Vercel Blob Storage.

  1. Install the @vercel/blob package
pnpm add @vercel/blob
  1. Assign a Vercel Blob Store to your project from the Vercel dashboard -> Project -> Storage
Files stored in Vercel Blob are always public. Manually configure a different storage driver if storing sensitive files.
  1. When running locally, you can set the BLOB_READ_WRITE_TOKEN environment variable to enable the Vercel Blob driver:
.env
BLOB_READ_WRITE_TOKEN=your-token
By default, the local filesystem driver is used if no automatic configuration is found.

Custom Driver

You can set a custom driver by providing a configuration object to blob.

nuxt.config.ts
export default defineNuxtConfig({
  hub: {
    blob: {
      driver: 'fs',
      dir: '.data/blob'
    }
  },
  // or overwrite only in production
  $production: {
    hub: {
      blob: {
        driver: 'cloudflare-r2',
        binding: 'BLOB'
      }
    }
  }
})
You can find the driver list on unstorage documentation with their configuration.

ensureBlob()

ensureBlob() is a handy util to validate a Blob by checking its size and type:

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']})

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 file doesn't meet the requirements.

Vue Composables

The following composables are meant to be used in the Vue side of your application (not the server/ directory).

useUpload()

useUpload is to handle file uploads in your Nuxt application.

<script setup lang="ts">
const upload = useUpload('/api/blob', { method: 'PUT' })

async function onFileSelect({ target }: Event) {
  const uploadedFiles = await upload(target as HTMLInputElement)

  // file uploaded successfully
}
</script>

<template>
  <input
    accept="image/jpeg, image/png"
    type="file"
    name="file"
    multiple
    @change="onFileSelect"
  >
</template>

Params

apiBase
string required
The base URL of the upload API.
options
Object required
Optionally, you can pass Fetch options to the request. Read more about Fetch API here.

Return

Return a MultipartUpload function that can be used to upload a file in parts.

const { completed, progress, abort } = upload(file)
const data = await completed

useMultipartUpload()

Application composable that creates a multipart upload helper.

When using the Vercel Blob driver, this utility will automatically use the Vercel Blob Client SDK to upload the file.
utils/multipart-upload.ts
export const mpu = useMultipartUpload('/api/files/multipart')

Params

baseURL
string
The base URL of the multipart upload API handled by handleMultipartUpload().
options
The options for the multipart upload helper.

Return

Return a MultipartUpload function that can be used to upload a file in parts.

const { completed, progress, abort } = mpu(file)
const data = await completed

Types

BlobObject

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

BlobMultipartUpload

export interface BlobMultipartUpload {
  pathname: string
  uploadId: string
  uploadPart(
    partNumber: number,
    value: string | ReadableStream<any> | ArrayBuffer | ArrayBufferView | Blob
  ): Promise<BlobUploadedPart>
  abort(): Promise<void>
  complete(uploadedParts: BlobUploadedPart[]): Promise<BlobObject>
}

BlobUploadedPart

export interface BlobUploadedPart {
  partNumber: number;
  etag: string;
}

MultipartUploader

export type MultipartUploader = (file: File) => {
  completed: Promise<SerializeObject<BlobObject> | undefined>
  progress: Readonly<Ref<number>>
  abort: () => Promise<void>
}

BlobListResult

interface BlobListResult {
  blobs: BlobObject[]
  hasMore: boolean
  cursor?: string
  folders?: string[]
}