File Storage
Upload handling, S3 compatible storage, and image optimization
File Storage
Handle file uploads with S3-compatible storage providers.
Supported Providers
- Cloudflare R2 (recommended)
- AWS S3
- DigitalOcean Spaces
- MinIO
- Backblaze B2
Configuration
Environment Variables
# Cloudflare R2
R2_ACCOUNT_ID=your-account-id
R2_ACCESS_KEY_ID=your-access-key
R2_SECRET_ACCESS_KEY=your-secret-key
R2_BUCKET_NAME=your-bucket
# Or AWS S3
S3_REGION=us-east-1
S3_ACCESS_KEY_ID=your-access-key
S3_SECRET_ACCESS_KEY=your-secret-key
S3_BUCKET_NAME=your-bucket
File Upload
Client-Side Upload
<script setup>
const file = ref(null)
async function uploadFile() {
const formData = new FormData()
formData.append('file', file.value)
const response = await $fetch('/api/upload', {
method: 'POST',
body: formData
})
console.log('File uploaded:', response.url)
}
</script>
<template>
<input type="file" @change="file = $event.target.files[0]">
<button @click="uploadFile">Upload</button>
</template>
Server-Side Handler
// server/api/upload.post.ts
export default defineEventHandler(async (event) => {
const form = await readMultipartFormData(event)
const file = form.find(item => item.name === 'file')
if (!file) {
throw createError({
statusCode: 400,
message: 'No file provided'
})
}
// Upload to storage
const url = await uploadFile(file)
return { url }
})
Image Optimization
// Resize and optimize image
import sharp from 'sharp'
const optimized = await sharp(file.data)
.resize(800, 600, { fit: 'inside' })
.jpeg({ quality: 80 })
.toBuffer()
await uploadFile(optimized, 'optimized-image.jpg')
Direct Upload (Pre-signed URLs)
// Generate pre-signed URL
const { uploadUrl, downloadUrl } = await $fetch('/api/upload/presigned', {
method: 'POST',
body: {
filename: 'document.pdf',
contentType: 'application/pdf'
}
})
// Upload directly to storage
await fetch(uploadUrl, {
method: 'PUT',
body: file,
headers: {
'Content-Type': 'application/pdf'
}
})
File Types
Allowed File Types
Configure allowed file types:
const allowedTypes = [
'image/jpeg',
'image/png',
'image/gif',
'image/webp',
'application/pdf',
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
]
function validateFileType(file: File) {
return allowedTypes.includes(file.type)
}
File Size Limits
const MAX_FILE_SIZE = 10 * 1024 * 1024 // 10MB
function validateFileSize(file: File) {
return file.size <= MAX_FILE_SIZE
}
Security Best Practices
- Validate file types and sizes
- Scan files for malware
- Use unique filenames to prevent overwriting
- Set appropriate CORS policies
- Use CDN for public files
- Implement rate limiting