6.4 KiB
Media Upload Setup
Type: page Date: 2026-01-11
Set up image uploads for the dashboard using ConvexFS and Bunny.net CDN.
ConvexFS Documentation
This media library is powered by ConvexFS, a virtual filesystem for Convex with CDN integration.
Resources:
- ConvexFS Documentation - Complete setup guides, API reference, and examples
- ConvexFS GitHub - Source code and issues
For detailed setup instructions including app configuration, garbage collection, file expiration, and advanced features, follow the official ConvexFS documentation.
Overview
The media library allows you to upload images directly from the dashboard and insert them into your content. Images are stored on Bunny.net Edge Storage and served via their global CDN for fast delivery.
Prerequisites
- A Bunny.net account
- Convex project deployed
- Access to Convex Dashboard environment variables
Create Bunny.net account
- Go to bunny.net and sign up
- Bunny offers a 14-day free trial with no credit card required
- After trial, storage costs around $0.01/GB/month
Create storage zone
- In the Bunny Dashboard, go to Storage in the sidebar
- Click Add Storage Zone
- Configure your storage zone:
- Name: Choose a unique name (e.g.,
mysite-media) - Main Storage Region: Select the region closest to your users
- Replication Regions: Optional, select additional regions for redundancy
- Name: Choose a unique name (e.g.,
- Click Create Storage Zone
Set up Pull Zone (CDN)
- After creating the storage zone, click Connected Pull Zone
- Create a new pull zone or connect to an existing one
- Note your Pull Zone Hostname (e.g.,
mysite-media.b-cdn.net) - Enable Token Authentication under Security settings for signed URLs
Get API credentials
From your Bunny Dashboard, collect these values:
| Credential | Location |
|---|---|
| API Key | Account > API > API Key (password icon) |
| Storage Zone Name | Storage > [Your Zone] > Name |
| CDN Hostname | Storage > [Your Zone] > Connected Pull Zone hostname |
| Token Key | Pull Zone > Security > Token Authentication > Token Key |
Add environment variables
Local development (.env.local)
Create or edit .env.local in your project root:
BUNNY_API_KEY=your-api-key-here
BUNNY_STORAGE_ZONE=your-zone-name
BUNNY_CDN_HOSTNAME=your-zone.b-cdn.net
BUNNY_TOKEN_KEY=your-token-key
Convex Dashboard
-
Go to your project in the Convex Dashboard
-
Navigate to Settings > Environment Variables
-
Add each of these variables:
BUNNY_API_KEYBUNNY_STORAGE_ZONEBUNNY_CDN_HOSTNAMEBUNNY_TOKEN_KEY(optional, for signed URLs)
-
Click Save
Deploy changes
After setting environment variables:
npx convex deploy
This pushes the ConvexFS configuration with your Bunny credentials.
Test upload workflow
- Go to Dashboard > Create > Media
- Click the upload zone or drag an image
- Verify the image appears in the grid
- Click MD to copy markdown and paste in a post
Using in content
Media Library
Access the Media Library from Dashboard sidebar under Create > Media. From here you can:
- Upload multiple images via drag-and-drop
- Copy markdown, HTML, or direct URL
- Select multiple images for bulk delete
- View file sizes
Bulk delete
To delete multiple images at once:
- Click the Select button in the toolbar
- Click images to select them (or use Select All)
- Click Delete (N) to remove selected images
- Confirm deletion in the dialog
Insert in editor
When writing a post or page in the dashboard:
- Click the Image button in the toolbar
- Choose Upload New to upload a new image, or Media Library to select an existing image
- After selecting/uploading, you'll see:
- Image preview with original dimensions (e.g., 1920 x 1080px)
- Alt text field for accessibility
- Size presets: Original, Large (1200px), Medium (800px), Small (400px), Thumbnail (200px), or Custom
- Choose a size - the display shows the calculated dimensions with aspect ratio preserved
- Click Insert to add the image to your content
Size options
| Preset | Max Width | Use Case |
|---|---|---|
| Original | Full size | High-resolution displays |
| Large | 1200px | Hero images, full-width content |
| Medium | 800px | Standard content images |
| Small | 400px | Thumbnails, sidebars |
| Thumbnail | 200px | Grids, galleries |
| Custom | Any | Specific dimensions needed |
When using a size other than Original, images are inserted with explicit width/height attributes to prevent layout shift.
Frontmatter images
For post header images, upload via Media Library then copy the URL:
---
title: "My Post"
image: https://your-zone.b-cdn.net/uploads/12345-image.png
---
Configuration options
In siteConfig.ts:
media: {
enabled: true, // Toggle media features
maxFileSize: 10, // Max file size in MB
allowedTypes: [ // Allowed MIME types
"image/png",
"image/jpeg",
"image/gif",
"image/webp"
],
}
Troubleshooting
"Upload failed" error
- Verify all four environment variables are set in Convex Dashboard
- Check that the API key has write permissions
- Ensure the storage zone name matches exactly
Images not loading
- Verify the CDN hostname is correct
- Check the Pull Zone is connected to your Storage Zone
- Try accessing the image URL directly in browser
403 Forbidden errors
- Token authentication may be blocking unsigned requests
- Either disable token auth in Pull Zone settings
- Or ensure
BUNNY_TOKEN_KEYis set correctly
Files uploading but not visible
- Check browser console for errors
- Verify the
/fs/uploadroute is registered inhttp.ts - Run
npx convex deployto sync configuration
File organization
Uploaded files are stored at /uploads/{timestamp}-{filename}:
/uploads/
1704067200000-hero-image.png
1704067201000-screenshot.jpg
1704067202000-diagram.webp
Timestamps ensure unique filenames and provide chronological ordering.
Cost estimate
Bunny.net pricing (as of 2024):
| Service | Cost |
|---|---|
| Storage | $0.01/GB/month |
| Bandwidth (EU/US) | $0.01/GB |
| Bandwidth (APAC) | $0.03/GB |
For a typical blog with 1GB of images and 10GB monthly bandwidth: ~$0.11/month.