Claude-skills vercel-blob
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.
install
source · Clone the upstream repo
git clone https://github.com/secondsky/claude-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/secondsky/claude-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/vercel-blob/skills/vercel-blob" ~/.claude/skills/secondsky-claude-skills-vercel-blob && rm -rf "$T"
manifest:
plugins/vercel-blob/skills/vercel-blob/SKILL.mdsource content
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
# In Vercel dashboard: Storage → Create Database → Blob vercel env pull .env.local
Creates:
BLOB_READ_WRITE_TOKEN
2. Install
bun add @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', contentType: file.type }); return blob.url; }
4. Basic Operations
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 to client |
Set explicitly | Correct browser handling for PDFs, videos |
Use for CDN caching | Private files bypass CDN |
| Validate file type and size before upload | Prevent invalid uploads |
| Use pathname organization | , , |
| Delete old files when replacing | Manage storage costs |
Never Do
| Rule | Why |
|---|---|
Expose to client | Security vulnerability |
| Upload files >500MB without multipart | Use API |
| Use generic filenames | Use or |
| Skip file validation | Always validate type/size |
| Store sensitive data unencrypted | Encrypt before upload |
| Forget to handle pagination | returns max 1000 files |
Known Issues Prevention
This skill prevents 10 documented issues:
| # | Error | Quick Fix |
|---|---|---|
| 1 | | Run |
| 2 | Client token exposed | Use for client uploads |
| 3 | File size exceeded (500MB) | Use multipart upload API |
| 4 | Wrong content-type | Set |
| 5 | No CDN caching | Use |
| 6 | Missing files in list | Use cursor pagination |
| 7 | Delete fails silently | Use exact URL from |
| 8 | Upload timeout | Use client-side upload for large files |
| 9 | Filename collisions | Add timestamp or |
| 10 | State not updated | Use 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 | , |
| Protected Upload | Private documents | with |
| Image Gallery | List & paginate | with cursor |
| Client Upload | Large files, progress | , |
| Multipart Upload | Files >500MB | , |
| Batch Operations | Multiple files | , |
| Image Processing | Optimize before upload | + |
See:
references/common-patterns.md for complete implementations.
Client-Side Upload (Essential Pattern)
Server Action (Token Generation):
'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:
'use client'; import { upload } from '@vercel/blob/client'; const blob = await upload(file.name, file, { access: 'public', handleUploadUrl: '/api/upload' });
Configuration
.env.local
# 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... |
|---|---|
| Debugging upload errors, token issues, or CDN caching problems |
| Implementing avatar uploads, galleries, client uploads, or multipart uploads |
Dependencies
{ "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 |
|---|---|
| Run |
| File size exceeded (>500MB) | Use multipart upload API |
| Client upload fails | Use server-side |
| Files not deleting | Use exact URL from response |
Token Savings: ~60% (patterns extracted to references) Error Prevention: 100% (all 10 documented issues) Ready for production!