Receber por email
← Voltar para o catálogo

vercel-blob

This skill provides comprehensive knowledge for integrating Vercel Blob object storage into Vercel applications. It should be used when setting up file uploads, managing images and documents, implementing CDN-delivered assets, or handling large files in Next.js serverless and edge functions. Use this skill when: - Setting up file uploads for Next.js applications (images, PDFs, videos) - Implementi

15estrelas
Atualizado há 11 meses

Ver no GitHub ↗ Licença: MIT

Como adicionar

/plugin marketplace add jackspace/ClaudeSkillz

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Para o autor da skill

Cole no README do seu repo

Mostra que sua skill está catalogada na Skillteca, gera backlink e tráfego rastreável.

[![Skillteca](https://www.skillteca.com.br/api/badge/vercel-blob/svg)](https://www.skillteca.com.br/skills/vercel-blob)

Skills relacionadas

Ver todas de Documentos →

Alerta por categoria

Receba novas skills de Documentos toda segunda

1 email curto, só com as skills novas de Documentos. 4 minutos de leitura, sem spam, cancela com 1 clique.

Você confirma o email no primeiro envio. Sem spam. Cancela com 1 clique.

Ler descrição completa

Vercel Blob (Object Storage)

Status: Production Ready Last Updated: 2025-10-29 Dependencies: None Latest Versions: @vercel/blob@2.0.0

Quick Start (3 Minutes)

1. Create Blob Store

# In Vercel dashboard: Storage → Create Database → Blob
vercel env pull .env.local

Creates: BLOB_READ_WRITE_TOKEN

2. Install

npm install @vercel/blob

3. Upload File (Server Action)

'use server';

import { put } from '@vercel/blob';

export async function uploadFile(formData: FormData) {
  const file = formData.get('file') as File;

  const blob = await put(file.name, file, {
    access: 'public' // or 'private'
  });

  return blob.url; // https://xyz.public.blob.vercel-storage.com/file.jpg
}

CRITICAL:

  • Use client upload tokens for direct client uploads (don't expose BLOB_READ_WRITE_TOKEN)
  • Set correct access level (public vs private)
  • Files are automatically distributed via CDN

The 5-Step Setup Process

Step 1: Create Blob Store

Vercel Dashboard:

  1. Project → Storage → Create Database → Blob
  2. Copy BLOB_READ_WRITE_TOKEN

Local Development:

vercel env pull .env.local

Creates .env.local:

BLOB_READ_WRITE_TOKEN="vercel_blob_rw_xxx"

Key Points:

  • Free tier: 100GB bandwidth/month
  • File size limit: 500MB per file
  • Automatic CDN distribution
  • Public files are cached globally

Step 2: Server-Side Upload

Next.js Server Action:

'use server';

import { put } from '@vercel/blob';

export async function uploadAvatar(formData: FormData) {
  const file = formData.get('avatar') as File;

  // Validate file
  if (!file.type.startsWith('image/')) {
    throw new Error('Only images allowed');
  }

  if (file.size > 5 * 1024 * 1024) {
    throw new Error('Max file size: 5MB');
  }

  // Upload
  const blob = await put(`avatars/${Date.now()}-${file.name}`, file, {
    access: 'public',
    addRandomSuffix: false
  });

  return {
    url: blob.url,
    pathname: blob.pathname
  };
}

API Route (Edge Runtime):

import { put } from '@vercel/blob';

export const runtime = 'edge';

export async function POST(request: Request) {
  const formData = await request.formData();
  const file = formData.get('file') as File;

  const blob = await put(file.name, file, { access: 'public' });

  return Response.json(blob);
}

Step 3: Client-Side Upload (Presigned URLs)

Create Upload Token (Server Action):

'use server';

import { handleUpload, type HandleUploadBody } from '@vercel/blob/client';

export async function getUploadToken(filename: string) {
  const jsonResponse = await handleUpload({
    body: {
      type: 'blob.generate-client-token',
      payload: {
        pathname: `uploads/${filename}`,
        access: 'public',
        onUploadCompleted: {
          callbackUrl: `${process.env.NEXT_PUBLIC_URL}/api/upload-complete`
        }
      }
    },
    request: new Request('https://dummy'),
    onBeforeGenerateToken: async (pathname) => {
      // Optional: validate user permissions
      return {
        allowedContentTypes: ['image/jpeg', 'image/png', 'image/webp'],
        maximumSizeInBytes: 5 * 1024 * 1024 // 5MB
      };
    },
    onUploadCompleted: async ({ blob, tokenPayload }) => {
      console.log('Upload completed:', blob.url);
    }
  });

  return jsonResponse;
}

Client Upload:

'use client';

import { upload } from '@vercel/blob/client';
import { getUploadToken } from './actions';

export function UploadForm() {
  async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
    e.preventDefault();
    const form = e.currentTarget;
    const file = (form.elements.namedItem('file') as HTMLInputElement).files?.[0];

    if (!file) return;

    const tokenResponse = await getUploadToken(file.name);

    const blob = await upload(file.name, file, {
      access: 'public',
      handleUploadUrl: tokenResponse.url
    });

    console.log('Uploaded:', blob.url);
  }

  return (
    <form onSubmit={handleSubmit}>
      <input type="file" name="file" required />
      <button type="submit">Upload</button>
    </form>
  );
}

Step 4: List, Download, Delete

List Files:

import { list } from '@vercel/blob';

const { blobs } = await list({
  prefix: 'avatars/',
  limit: 100
});

// Returns: { url, pathname, size, uploadedAt, ... }[]

List with Pagination:

let cursor: string | undefined;
const allBlobs = [];

do {
  const { blobs, cursor: nextCursor } = await list({
    prefix: 'uploads/',
    cursor
  });
  allBlobs.push(...blobs);
  cursor = nextCursor;
} while (cursor);

Download File:

// Files are publicly accessible if access: 'public'
const url = 'https://xyz.public.blob.vercel-storage.com/file.pdf';
const response = await fetch(url);
const blob = await response.blob();

Delete File:

import { del } from '@vercel/blob';

await del('https://xyz.public.blob.vercel-storage.com/file.jpg');

// Or delete multiple
await del([url1, url2, url3]);

Step 5: Streaming & Multipart

Streaming Upload:

import { put } from '@vercel/blob';
import { createReadStream } from 'fs';

const stream = createReadStream('./large-file.mp4');

const blob = await put('videos/large-file.mp4', stream, {
  access: 'public',
  contentType: 'video/mp4'
});

Multipart Upload (Large Files >500MB):

import { createMultipartUpload, uploadPart, completeMultipartUpload } from '@vercel/blob';

// 1. Start multipart upload
const upload = await createMultipartUpload('large-video.mp4', {
  access: 'public'
});

// 2. Upload parts (chunks)
const partSize = 100 * 1024 * 1024; // 100MB chunks
const parts = [];

for (let i = 0; i < totalParts; i++) {
  const chunk = getChunk(i, partSize);
  const part = await uploadPart(chunk, {
    uploadId: upload.uploadId,
    partNumber: i + 1
  });
  parts.push(part);
}

// 3. Complete upload
const blob = await completeMultipartUpload({
  uploadId: upload.uploadId,
  parts
});

Critical Rules

Always Do

✅ Use client upload tokens for client-side uploads - Never expose BLOB_READ_WRITE_TOKEN to client

✅ Set correct access level - public (CDN) or private (authenticated access)

✅ Validate file types and sizes - Before upload, check MIME type and size

✅ Use pathname organization - avatars/, uploads/, documents/ for structure

✅ Handle upload errors - Network failures, size limits, token expiration

✅ Clean up old files - Delete unused files to manage storage costs

✅ Set content-type explicitly - For correct browser handling (videos, PDFs)

Never Do

❌ Never expose BLOB_READ_WRITE_TOKEN to client - Use handleUpload() for client uploads

❌ Never skip file validation - Always validate type, size, content before upload

❌ Never upload files >500MB without multipart - Use multipart upload for large files

❌ Never use generic filenames - file.jpg collides, use ${timestamp}-${name} or UUID

❌ Never assume uploads succeed - Always handle errors (network, quota, etc.)

❌ Never store sensitive data unencrypted - Encrypt before upload if needed

❌ Never forget to delete temporary files - Old uploads consume quota

Known Issues Prevention

This skill prevents 10 documented issues:

Issue #1: Missing Environment Variable

Error: Error: BLOB_READ_WRITE_TOKEN is not defined Source: https://vercel.com/docs/storage/vercel-blob Why It Happens: Token not set in environment Prevention: Run vercel env pull .env.local and ensure .env.local in .gitignore.

Issue #2: Client Upload Token Exposed

Error: Security vulnerability, unauthorized uploads Source: https://vercel.com/docs/storage/vercel-blob/client-upload Why It Happens: Using BLOB_READ_WRITE_TOKEN direc

Compartilhar X LinkedIn