Chapter 5: File Management
Chapter 5: File Management
Vibe CMS provides a robust file management system designed for modern web applications. This chapter covers everything from uploading files to organizing assets, optimizing images, and serving them efficiently through CDN-friendly URLs.
Overview
The file management system in Vibe CMS includes:
- Multiple upload methods: Direct upload, URL download, and token-based uploads
- Intelligent deduplication: SHA-256 hashing prevents duplicate storage
- Folder organization: Hierarchical folder structure for logical asset organization
- Rich metadata: SEO fields, descriptions, and technical metadata
- Automatic image optimization: Multiple variants generated automatically
- CDN-ready serving: Public asset URLs optimized for global delivery
File Upload System
Upload Methods
Vibe CMS supports three primary upload methods:
1. URL-Based Upload
Download a file from a URL and upload it to your CMS:
result = mcp.upload_file_from_url(
url="https://images.unsplash.com/photo-1234567890",
filename="hero-image.jpg",
folder_path="/images/heroes",
title="Homepage Hero Image",
alt_text="Modern office workspace with natural lighting",
focus_keyword="workspace design",
description="Hero image for homepage featuring collaborative workspace"
)
file_id = result["file_id"]
public_url = result["public_url"]
Allowed domains for URL downloads include:
example.comimages.unsplash.compicsum.photos- And other configured domains
2. Token-Based Upload (Direct Client Upload)
For direct uploads from client applications without exposing API credentials:
Step 1: Request an upload token
token_response = mcp.request_upload_token(
filename="presentation.pdf",
mime_type="application/pdf",
file_size=2048576, # 2MB in bytes
folder_path="/documents/2024",
title="Q1 Product Presentation",
alt_text="Q1 2024 product roadmap presentation"
)
upload_url = token_response["upload_url"]
file_id = token_response["file_id"]
Step 2: Upload file directly via HTTP PUT
// Client-side JavaScript example
const file = document.querySelector('input[type="file"]').files[0];
const response = await fetch(uploadUrl, {
method: 'PUT',
body: file,
headers: {
'Content-Type': file.type
}
});
if (response.ok) {
console.log('Upload successful! File ID:', fileId);
}
This method is ideal for:
- Browser-based uploads
- Mobile applications
- Serverless architectures
- Scenarios where you want to avoid proxying large files through your backend
3. Local File Upload (SDK)
When using the TypeScript or Python SDK directly:
import { VibeCMS } from '@vibe-cms/sdk';
const cms = new VibeCMS({
apiUrl: process.env.VIBE_API_URL,
projectId: process.env.VIBE_PROJECT_ID,
apiKey: process.env.VIBE_API_KEY
});
const result = await cms.uploadFile({
file: fileBuffer,
filename: 'logo.png',
mimeType: 'image/png',
folderPath: '/images/branding',
title: 'Company Logo',
altText: 'Acme Corporation Logo'
});
File Size Limits
- Maximum file size: 52,428,800 bytes (50 MB)
- Files exceeding this limit will be rejected
- Consider compression for large images or videos
File Deduplication
Vibe CMS uses SHA-256 hashing to prevent duplicate file storage:
- When a file is uploaded, its SHA-256 hash is calculated
- If a file with the same hash already exists, the system:
- Creates a new file record with metadata
- Links to the existing physical file
- Saves storage space automatically
- Each file record can have unique metadata even if sharing the same physical file
This means:
- ✅ Same image can have different titles, alt text, or descriptions
- ✅ Storage costs are minimized
- ✅ Upload speed is faster for duplicate files
- ✅ No manual deduplication needed
Supported MIME Types
Vibe CMS supports all standard MIME types including:
Images:
image/jpeg,image/jpgimage/pngimage/gifimage/webpimage/svg+xml
Documents:
application/pdfapplication/mswordapplication/vnd.openxmlformats-officedocument.wordprocessingml.documenttext/plain
Media:
video/mp4audio/mpegaudio/wav
Archives:
application/zipapplication/x-tar
And many more standard types.
File Organization
Folder Structure
Folders in Vibe CMS use a path-based hierarchy similar to filesystem directories:
/
├── images/
│ ├── heroes/
│ ├── products/
│ └── team/
├── documents/
│ ├── 2024/
│ │ ├── contracts/
│ │ └── reports/
│ └── 2023/
└── media/
├── videos/
└── audio/
Creating Folders
# Create a top-level folder
result = mcp.manage_folder(
action="create",
path="/images"
)
# Create nested folders
result = mcp.manage_folder(
action="create",
path="/documents/2024/contracts"
)
Important: Parent folders must exist before creating nested folders.
Listing Folders
# List all folders
all_folders = mcp.folders()
# List folders in a specific parent path
image_folders = mcp.folders(parent_path="/images")
doc_folders = mcp.folders(parent_path="/documents/2024")
Response format:
{
"folders": [
{"path": "/images", "created_at": "2024-01-15T10:30:00Z"},
{"path": "/images/heroes", "created_at": "2024-01-15T10:31:00Z"}
],
"count": 2,
"filter_applied": {
"parent_path": "/images"
}
}
Renaming Folders
result = mcp.manage_folder(
action="update",
path="/images/heros", # Old path (typo)
new_path="/images/heroes" # Corrected path
)
Note: Renaming a folder updates all file paths within it automatically.
Deleting Folders
# Requires confirmation to prevent accidental deletion
result = mcp.manage_folder(
action="delete",
path="/temp",
confirm_delete=True
)
Warning: Deleting a folder does NOT delete the files within it. Files will remain but their folder path will be cleared.
Moving Files Between Folders
Move a file by updating its folder_path metadata:
result = mcp.manage_file(
action="update",
file_id="f47ac10b-58cc-4372-a567-0e02b2c3d479",
folder_path="/images/archived"
)
File Metadata
Core Metadata Fields
Every file in Vibe CMS has comprehensive metadata:
{
"id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"filename": "hero-image.jpg",
"mime_type": "image/jpeg",
"file_size": 245760, # bytes
"folder_path": "/images/heroes",
"sha256_hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
# Descriptive metadata
"title": "Homepage Hero Image",
"description": "Modern office workspace featuring collaboration",
"caption": "Our team collaborating on innovative solutions",
# SEO metadata
"alt_text": "Modern office workspace with natural lighting",
"focus_keyword": "workspace design",
# Image-specific metadata
"width": 1920,
"height": 1080,
# System metadata
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T14:22:00Z",
"public_url": "https://assets.vibecms.com/..."
}
Metadata Field Descriptions
| Field | Type | Description | Required |
|---|---|---|---|
filename |
string | Original filename | Yes |
mime_type |
string | MIME type (e.g., image/jpeg) |
Yes |
file_size |
integer | Size in bytes | Yes (auto) |
folder_path |
string | Folder location (e.g., /images) |
No |
title |
string | Display title for CMS | No |
description |
string | Detailed description | No |
caption |
string | Brief caption text | No |
alt_text |
string | SEO alt text for images | No |
focus_keyword |
string | Primary SEO keyword | No |
width |
integer | Image width in pixels | Auto |
height |
integer | Image height in pixels | Auto |
sha256_hash |
string | SHA-256 hash for deduplication | Yes (auto) |
Updating File Metadata
result = mcp.manage_file(
action="update",
file_id="f47ac10b-58cc-4372-a567-0e02b2c3d479",
title="Updated Hero Image",
alt_text="Team members collaborating in modern workspace",
focus_keyword="team collaboration",
description="Updated description with more detail",
caption="Innovation through collaboration",
folder_path="/images/heroes/2024"
)
Note: You can update any combination of fields in a single call. Only provided fields will be updated.
Image Optimization and Transformations
Automatic Image Optimization
When an image is uploaded, Vibe CMS automatically:
- Analyzes the image - Extracts width, height, and format
- Generates variants - Creates optimized versions for different use cases
- Optimizes file size - Compresses without significant quality loss
- Calculates hash - SHA-256 for deduplication
File Variants System
Vibe CMS generates multiple variants of each image:
# Variant configuration examples
variants = {
"thumbnail": {
"width": 150,
"height": 150,
"format": "webp"
},
"medium": {
"width": 800,
"height": 600,
"format": "webp"
},
"large": {
"width": 1920,
"height": 1080,
"format": "webp"
}
}
Variant Storage
Variants are stored in the cms_file_variants table:
CREATE TABLE cms_file_variants (
id UUID PRIMARY KEY,
file_id UUID REFERENCES cms_files(id),
variant_name VARCHAR(100), -- e.g., 'thumbnail', 'medium', 'large'
width INTEGER,
height INTEGER,
file_size INTEGER,
storage_path TEXT,
created_at TIMESTAMP
);
Accessing Variants
When retrieving file metadata, variants are included:
file_data = mcp.files(file_id="f47ac10b-58cc-4372-a567-0e02b2c3d479")
print(file_data["variants"])
# [
# {
# "name": "thumbnail",
# "width": 150,
# "height": 150,
# "url": "https://assets.vibecms.com/.../thumbnail.webp"
# },
# {
# "name": "medium",
# "width": 800,
# "height": 600,
# "url": "https://assets.vibecms.com/.../medium.webp"
# }
# ]
Preview Generation
Generate a 512x512 preview for image files:
preview = mcp.get_file_preview(
file_id="f47ac10b-58cc-4372-a567-0e02b2c3d479"
)
# Returns base64-encoded image data or preview URL
preview_url = preview["preview_url"]
Use cases:
- Admin interface thumbnails
- Quick image previews
- Gallery grids
- File selection dialogs
On-Demand Transformations
For custom transformations beyond predefined variants, use URL parameters:
https://assets.vibecms.com/files/{file_id}?w=400&h=300&fit=cover&format=webp
Supported parameters:
w- Width in pixelsh- Height in pixelsfit- Resize mode:cover,contain,fill,inside,outsideformat- Output format:webp,jpeg,png,avifquality- Quality: 1-100
Asset Serving
Public Asset URLs
Every file has a public URL for serving:
file_data = mcp.files(file_id="f47ac10b-58cc-4372-a567-0e02b2c3d479")
public_url = file_data["public_url"]
# Example URL:
# https://assets.vibecms.com/projects/proj_abc123/files/f47ac10b-58cc-4372-a567-0e02b2c3d479/hero-image.jpg
CDN-Friendly URLs
Asset URLs are optimized for CDN caching:
- Consistent URLs - Same file always has the same URL
- Cache headers - Long cache times with proper invalidation
- Global distribution - Served from edge locations worldwide
- HTTPS by default - Secure asset delivery
SDK Asset URL Generation
The TypeScript SDK provides helper methods:
import { cms } from './lib/cms';
// Get file metadata including public URL
const file = await cms.getFile('f47ac10b-58cc-4372-a567-0e02b2c3d479');
const url = file.publicUrl;
// Get specific variant URL
const thumbnailUrl = file.variants.find(v => v.name === 'thumbnail')?.url;
Serving Optimized Images
Best practices for serving images:
<!-- Use appropriate variant for context -->
<img
src="{medium_variant_url}"
srcset="
{thumbnail_url} 150w,
{medium_url} 800w,
{large_url} 1920w
"
sizes="(max-width: 600px) 150px, (max-width: 1200px) 800px, 1920px"
alt="{alt_text}"
loading="lazy"
/>
Downloading Assets Programmatically
import requests
file_data = mcp.files(file_id="f47ac10b-58cc-4372-a567-0e02b2c3d479")
public_url = file_data["public_url"]
# Download the file
response = requests.get(public_url)
with open('downloaded_file.jpg', 'wb') as f:
f.write(response.content)
File Management Operations
Listing Files
List all files:
all_files = mcp.files()
print(f"Total files: {all_files['count']}")
for file in all_files['files']:
print(f"{file['filename']} - {file['mime_type']}")
Filter by folder:
image_files = mcp.files(folder_path="/images")
contract_files = mcp.files(folder_path="/documents/2024/contracts")
Filter by MIME type:
# All images
images = mcp.files(mime_type="image/")
# Specific image type
jpegs = mcp.files(mime_type="image/jpeg")
# PDFs only
pdfs = mcp.files(mime_type="application/pdf")
Combine filters:
product_images = mcp.files(
folder_path="/images/products",
mime_type="image/"
)
Getting File Metadata
# Get specific file by ID
file_data = mcp.files(file_id="f47ac10b-58cc-4372-a567-0e02b2c3d479")
print(f"Filename: {file_data['filename']}")
print(f"Size: {file_data['file_size']} bytes")
print(f"Public URL: {file_data['public_url']}")
print(f"Variants: {len(file_data['variants'])}")
Updating Files
Update metadata without changing the file itself:
result = mcp.manage_file(
action="update",
file_id="f47ac10b-58cc-4372-a567-0e02b2c3d479",
title="Q1 2024 Product Launch Hero",
alt_text="Innovative product showcase with modern design",
focus_keyword="product innovation",
description="Hero image for Q1 product launch campaign",
folder_path="/images/campaigns/2024-q1"
)
Deleting Files
# Permanent deletion - requires confirmation
result = mcp.manage_file(
action="delete",
file_id="f47ac10b-58cc-4372-a567-0e02b2c3d479",
confirm_delete=True
)
Warning:
- File deletion is permanent and cannot be undone
- All variants are also deleted
- Content items referencing this file will have broken references
- The physical file is deleted only if no other file records reference it (due to deduplication)
File Search and Filtering
Advanced search patterns:
# Find all team photos from 2024
team_photos = mcp.files(
folder_path="/images/team",
mime_type="image/"
)
# Filter results by filename pattern
import re
headshots = [
f for f in team_photos['files']
if re.search(r'headshot', f['filename'], re.IGNORECASE)
]
# Find large files (>5MB)
large_files = [
f for f in all_files['files']
if f['file_size'] > 5 * 1024 * 1024
]
MCP Tools for File Management
files() - List and Get File Metadata
# List all files
mcp.files()
# Get specific file
mcp.files(file_id="f47ac10b-...")
# Filter by folder
mcp.files(folder_path="/images")
# Filter by MIME type
mcp.files(mime_type="image/png")
# Combine filters
mcp.files(folder_path="/images/products", mime_type="image/")
Returns:
- Single file:
{id, filename, mime_type, file_size, public_url, variants, ...} - Multiple files:
{files: [...], count: N, filter_applied: {...}}
manage_file() - Update or Delete Files
# Update metadata
mcp.manage_file(
action="update",
file_id="f47ac10b-...",
title="New Title",
alt_text="Updated alt text",
focus_keyword="keyword",
description="Updated description",
caption="Updated caption",
folder_path="/new/folder"
)
# Delete file
mcp.manage_file(
action="delete",
file_id="f47ac10b-...",
confirm_delete=True
)
get_file_preview() - Generate Image Previews
# Get 512x512 preview
preview = mcp.get_file_preview(
file_id="f47ac10b-58cc-4372-a567-0e02b2c3d479"
)
preview_url = preview["preview_url"]
Only works for image files - Returns error for non-image types.
upload_file_from_url() - Download and Upload from URL
result = mcp.upload_file_from_url(
url="https://images.unsplash.com/photo-123...",
filename="hero.jpg", # Optional, auto-detected if omitted
mime_type="image/jpeg", # Optional, auto-detected if omitted
folder_path="/images/heroes",
title="Homepage Hero",
alt_text="Modern workspace design",
focus_keyword="workspace",
description="Hero image for homepage",
caption="Innovation in action"
)
file_id = result["file_id"]
public_url = result["public_url"]
request_upload_token() - Get Token for Direct Upload
token = mcp.request_upload_token(
filename="document.pdf",
mime_type="application/pdf",
file_size=2048576, # Required: size in bytes
folder_path="/documents",
title="Contract Document",
alt_text="Q1 2024 Service Contract"
)
upload_url = token["upload_url"] # Use for HTTP PUT
file_id = token["file_id"] # File ID for later reference
Maximum file size: 52,428,800 bytes (50 MB)
folders() - List Folders
# List all folders
mcp.folders()
# List folders in specific parent
mcp.folders(parent_path="/images")
mcp.folders(parent_path="/documents/2024")
Returns: {folders: [...], count: N, filter_applied: {...}}
manage_folder() - Create, Rename, Delete Folders
# Create folder
mcp.manage_folder(
action="create",
path="/images/products"
)
# Rename folder
mcp.manage_folder(
action="update",
path="/images/prodcuts", # Old path
new_path="/images/products" # New path
)
# Delete folder
mcp.manage_folder(
action="delete",
path="/temp",
confirm_delete=True
)
Best Practices
File Naming Conventions
DO:
- ✅ Use descriptive, lowercase names:
team-photo-john-smith.jpg - ✅ Use hyphens instead of spaces:
product-hero-2024.png - ✅ Include context in filename:
blog-header-ai-trends.jpg - ✅ Use consistent date format:
report-2024-03-15.pdf - ✅ Keep names concise but meaningful
DON'T:
- ❌ Avoid spaces:
team photo.jpg→team-photo.jpg - ❌ Avoid special characters:
image@#$%.jpg - ❌ Don't use generic names:
image1.jpg,photo.png - ❌ Avoid very long names (>100 characters)
Folder Organization Strategies
By Content Type:
/images/
/videos/
/documents/
/downloads/
By Date:
/images/2024/01/
/images/2024/02/
/documents/2024/q1/
By Purpose:
/marketing/campaigns/2024-q1/
/marketing/social-media/
/product/screenshots/
/team/headshots/
Hybrid Approach (Recommended):
/images/
├── marketing/
│ ├── campaigns/2024-q1/
│ └── social/
├── products/
│ ├── screenshots/
│ └── packaging/
└── team/
/documents/
├── 2024/
│ ├── contracts/
│ └── reports/
└── templates/
SEO Metadata Optimization
Alt Text Best Practices:
# Good alt text
alt_text = "Woman presenting data analytics on laptop to team in modern office"
# Bad alt text
alt_text = "image" # Too generic
alt_text = "photo-123.jpg" # Just filename
alt_text = "" # Empty (never do this for content images)
Focus Keyword Strategy:
# Target 1-3 keywords that describe the image
focus_keyword = "data analytics presentation"
# Use in alt text naturally
alt_text = "Team reviewing data analytics presentation on laptop"
Title and Description:
title = "Q1 Analytics Review Meeting" # Brief, descriptive
description = "Marketing team reviewing Q1 performance metrics and analytics data to plan Q2 strategy" # Detailed context
caption = "Strategic planning in action" # Short, engaging
Image Optimization Guidelines
Before Upload:
- Resize appropriately - Don't upload 4K images for thumbnails
- Compress images - Use tools like ImageOptim, TinyPNG
- Choose right format:
- Photos: JPEG or WebP
- Graphics/logos: PNG or SVG
- Animations: GIF or WebP
After Upload:
- Use appropriate variants - Thumbnail for grids, medium for content, large for hero images
- Leverage lazy loading - Don't load images until needed
- Implement responsive images - Use
srcsetandsizes
Target sizes:
- Thumbnails: 150-300px wide
- Content images: 600-1200px wide
- Hero images: 1920px wide maximum
- File size: < 200KB for most images
Security Considerations
File Upload Security:
- ✅ Validate MIME types server-side
- ✅ Scan uploaded files for malware
- ✅ Limit file sizes (50 MB maximum)
- ✅ Use upload tokens for client-side uploads
- ✅ Never expose API keys in client code
Access Control:
- ✅ Public URLs are publicly accessible (by design)
- ✅ Use private storage for sensitive documents
- ✅ Don't upload confidential information to public CMS
- ✅ Review folder permissions regularly
File Deletion:
- ✅ Always require confirmation for deletion
- ✅ Audit file deletions
- ✅ Consider soft-delete for recovery options
- ✅ Check content references before deleting
Performance Tips
Optimize Asset Delivery:
<!-- Use WebP with fallback -->
<picture>
<source srcset="{webp_url}" type="image/webp">
<img src="{jpeg_url}" alt="{alt_text}" loading="lazy">
</picture>
Batch Operations:
# Fetch all files once
all_files = mcp.files(folder_path="/images/products")
# Process in batches
for file in all_files['files']:
# Update metadata
mcp.manage_file(
action="update",
file_id=file['id'],
focus_keyword="product showcase"
)
Cache Metadata:
# Cache file metadata in your application
import functools
import time
@functools.lru_cache(maxsize=1000)
def get_cached_file(file_id, cache_time=3600):
return mcp.files(file_id=file_id)
# Use cached version
file_data = get_cached_file("f47ac10b-...")
CDN Configuration:
- Set long cache times for immutable assets
- Use query parameters for cache busting:
?v=2024-03-15 - Configure edge caching for global distribution
- Enable compression (gzip, brotli) at CDN level
Summary
You've learned:
✅ Upload Methods - URL download, token-based upload, direct SDK upload
✅ Deduplication - SHA-256 hashing prevents duplicate storage
✅ Organization - Hierarchical folder structure with path-based navigation
✅ Metadata - Rich SEO and descriptive metadata for all files
✅ Image Optimization - Automatic variant generation and on-demand transformations
✅ Asset Serving - CDN-friendly public URLs with global delivery
✅ MCP Tools - Complete file and folder management via MCP interface
✅ Best Practices - Naming conventions, SEO optimization, security, performance
Next Steps
- Chapter 6: Collections Deep Dive - Advanced collection patterns and field types
- Chapter 7: Content Relationships - Linking files to content items
- Chapter 8: SDK Integration - Using files in your frontend application