vercel-blob — quality + safety report
In the Skillier index (secondsky__vercel-blob) · scanned 2026-06-03 · engine: builtin+triage
1 heuristic flag to review
Heuristic flags from the builtin scanner, which is known to over-flag (it trips on legitimate env-reading integrations, security skills, and library .eval calls). This is NOT an authoritative malicious verdict — re-scan with SkillSpector for the authoritative result. Run the authoritative scan →
📇 This skill is in the Skillier index (curated · deduped · quality-filtered). Install Skillier to route & load it into your AI client.
Quality notes
About this skill
Vercel Blob object storage with CDN for Next.js. Use for file uploads images, PDFs, videos , presigned URLs, user-generated content, file management, or encountering BLOB READ WRITE TOKEN errors, file size limits, client upload token errors.
📄 Read the SKILL.md
---
name: vercel-blob
description: "Vercel Blob object storage with CDN for Next.js. Use for file uploads (images, PDFs, videos), presigned URLs, user-generated content, file management, or encountering BLOB_READ_WRITE_TOKEN errors, file size limits, client upload token errors."
metadata:
keywords:
- vercel blob
- "@vercel/blob"
- vercel storage
- vercel file upload
- vercel cdn
- blob storage vercel
- client upload vercel
- presigned url vercel
- file upload nextjs
- image upload vercel
- pdf upload
- video upload
- user uploads
- multipart upload
- streaming upload
- blob cdn
- vercel assets
- file download
license: MIT
---
# Vercel Blob (Object Storage)
**Status**: Production Ready
**Last Updated**: 2025-12-14
**Dependencies**: None
**Latest Versions**: `@vercel/blob@2.0.0`
---
## Quick Start (3 Minutes)
### 1. Create & Configure
```bash
# In Vercel dashboard: Storage → Create Database → Blob
vercel env pull .env.local
```
Creates: `BLOB_READ_WRITE_TOKEN`
### 2. Install
```bash
bun add @vercel/blob
```
### 3. Upload File (Server Action)
```typescript
'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',
contentType: file.type
});
return blob.url;
}
```
### 4. Basic Operations
```typescript
import { put, del, list } from '@vercel/blob';
// Upload
const blob = await put('path/file.jpg', file, { access: 'public' });
// Delete
await del(blob.url);
// List with pagination
const { blobs, cursor } = await list({ prefix: 'uploads/', limit: 100 });
```
---
## Critical Rules
### Always Do
| Rule | Why |
|------|-----|
| Use client upload tokens for client-side uploads | Never expose `BLOB_READ_WRITE_TOKEN` to client |
| Set `contentType` explicitly | Correct browser handling for PDFs, videos |
| Use `access: 'public'` for CDN caching | Private files bypass CDN |
| Validate file type and size before upload | Prevent invalid uploads |
| Use pathname organization | `avatars/`, `uploads/`, `documents/` |
| Delete old files when replacing | Manage storage costs |
### Never Do
| Rule | Why |
|------|-----|
| Expose `BLOB_READ_WRITE_TOKEN` to client | Security vulnerability |
| Upload files >500MB without multipart | Use `createMultipartUpload` API |
| Use generic filenames | Use `${Date.now()}-${name}` or `addRandomSuffix: true` |
| Skip file validation | Always validate type/size |
| Store sensitive data unencrypted | Encrypt before upload |
| Forget to handle pagination | `list()` returns max 1000 files |
---
## Known Issues Prevention
This skill prevents **10 documented issues**:
| # | Error | Quick Fix |
|---|-------|-----------|
| 1 | `BLOB_READ_WRITE_TOKEN not defined` | Run `vercel env pull .env.local` |
| 2 | Client token exposed | Use `handleUpload()` for client uploads |
| 3 | File size exceeded (500MB) | Use multipart upload API |
| 4 | Wrong content-type | Set `contentType: file.type` |
| 5 | No CDN caching | Use `access: 'public'` |
| 6 | Missing files in list | Use cursor pagination |
| 7 | Delete fails silently | Use exact URL from `put()` |
| 8 | Upload timeout | Use client-side upload for large files |
| 9 | Filename collisions | Add timestamp or `addRandomSuffix: true` |
| 10 | State not updated | Use `onUploadCompleted` callback |
**See**: `references/known-issues.md` for complete solutions with code examples.
---
## Common Patterns Summary
| Pattern | Use Case | Key API |
|---------|----------|---------|
| **Avatar Upload** | User profile images | `put`, `del` |
| **Protected Upload** | Private documents | `put` with `access: 'private'` |
| **Image Gallery** | List & paginate | `list` with cursor |
| **Client Upload** | Large files, progress | `upload`, `handleUpload` |
| **Multipart Upload** | Files >500MB | `createMultipartUpload`, `uploadPart` |
| **Batch Operations** | Multiple files | `Promise.all`, `del([...])` |
| **Image Processing** | Optimize before upload | `sharp` + `put` |
**See**: `references/common-patterns.md` for complete implementations.
---
## Client-Side Upload (Essential Pattern)
**Server Action (Token Generation):**
```typescript
'use server';
import { handleUpload, type HandleUploadBody } from '@vercel/blob/client';
export async function generateUploadToken(body: HandleUploadBody) {
return await handleUpload({
body,
request: new Request('https://dummy'),
onBeforeGenerateToken: async (pathname) => ({
allowedContentTypes: ['image/jpeg', 'image/png', 'image/webp'],
maximumSizeInBytes: 5 * 1024 * 1024
}),
onUploadCompleted: async ({ blob }) => {
// Save to database
await db.insert(uploads).values({ url: blob.url, pathname: blob.pathname });
}
});
}
```
**Client Component:**
```typescript
'use client';
import { upload } from '@vercel/blob/client';
const blob = await upload(file.name, file, {
access: 'public',
handleUploadUrl: '/api/upload'
});
```
---
## Configuration
### .env.local
```bash
# Created by: vercel env pull .env.local
BLOB_READ_WRITE_TOKEN="vercel_blob_rw_xxxxx"
```
### .gitignore
```
.env.local
.env*.local
```
---
## When to Load References
| Reference | Load When... |
|-----------|--------------|
| `references/known-issues.md` | Debugging upload errors, token issues, or CDN caching problems |
| `references/common-patterns.md` | Implementing avatar uploads, galleries, client uploads, or multipart uploads |
---
## Dependencies
```json
{
"dependencies": {
"@vercel/blob": "^2.0.0"
}
}
```
**Free Tier Limits**: 100GB bandwidth/month, 500MB max file size
---
## Official Documentation
- **Vercel Blob**: https://vercel.com/docs/storage/vercel-blob
- **Client Upload**: https://vercel.com/docs/storage/vercel-blob/client-upload
- **SDK Reference**: https://vercel.com/docs/storage/vercel-blob/using-blob-sdk
- **GitHub**: https://github.com/vercel/storage
---
## Troubleshooting
| Problem | Solution |
|---------|----------|
| `BLOB_READ_WRITE_TOKEN not defined` | Run `vercel env pull .env.local` |
| File size exceeded (>500MB) | Use multipart upload API |
| Client upload fails | Use `handleUpload()` server-side |
| Files not deleting | Use exact URL from `put()` response |
---
**Token Savings**: ~60% (patterns extracted to references)
**Error Prevention**: 100% (all 10 documented issues)
**Ready for production!**Want a live grade + an embeddable README badge? Run your skill through the free scanner.
Graded independently by Skillproof — nothing to sell the author. Quality is mechanical + corpus-grounded; safety flags are heuristic (builtin+triage), not a malicious verdict.