File Storage Plugin
Upload and manage files with support for local storage and cloud providers.
Supported Providers
| Provider | Description |
|---|---|
| Local | File system storage |
| AWS S3 | Amazon S3 |
| Cloudflare R2 | S3-compatible storage |
| DigitalOcean Spaces | S3-compatible |
| Backblaze B2 | Affordable cloud storage |
Installation
npx autodeploybase add file-storage
Configuration
autodeploy.config.json
{
"plugins": {
"file-storage": {
"enabled": true,
"settings": {
"provider": "s3",
"bucket": "my-app-uploads",
"maxFileSize": 10485760,
"allowedTypes": ["image/*", "application/pdf"]
}
}
}
}
Environment Variables
AWS S3
STORAGE_PROVIDER=s3
S3_BUCKET=my-bucket
S3_REGION=us-east-1
S3_ACCESS_KEY=AKIA...
S3_SECRET_KEY=...
S3_ENDPOINT= # Optional, for S3-compatible services
Cloudflare R2
STORAGE_PROVIDER=r2
R2_ACCOUNT_ID=...
R2_ACCESS_KEY=...
R2_SECRET_KEY=...
R2_BUCKET=my-bucket
Local
STORAGE_PROVIDER=local
STORAGE_PATH=./uploads
Usage
Upload File
import { uploadFile } from '@/plugins/file-storage';
// From request
export async function POST(request: Request) {
const formData = await request.formData();
const file = formData.get('file') as File;
const result = await uploadFile(file, {
folder: 'avatars',
generateUniqueName: true
});
return Response.json({
url: result.url,
key: result.key,
size: result.size
});
}
Upload Buffer
import { uploadBuffer } from '@/plugins/file-storage';
const buffer = await generatePDF(data);
const result = await uploadBuffer(buffer, {
filename: 'report.pdf',
contentType: 'application/pdf',
folder: 'reports'
});
Get File URL
import { getFileUrl } from '@/plugins/file-storage';
// Public URL
const url = await getFileUrl('avatars/user-123.jpg');
// Signed URL (temporary access)
const signedUrl = await getFileUrl('private/document.pdf', {
signed: true,
expiresIn: 3600 // 1 hour
});
Delete File
import { deleteFile } from '@/plugins/file-storage';
await deleteFile('avatars/old-avatar.jpg');
List Files
import { listFiles } from '@/plugins/file-storage';
const files = await listFiles({
prefix: 'avatars/',
maxKeys: 100
});
// files: [{ key, size, lastModified }, ...]
React Components
FileUpload
import { FileUpload } from '@/plugins/file-storage/components';
export function AvatarUploader() {
const handleUpload = async (file: File) => {
const result = await uploadFile(file, { folder: 'avatars' });
console.log('Uploaded:', result.url);
};
return (
<FileUpload accept="image/*" maxSize={5 * 1024 * 1024} onUpload={handleUpload}>
<p>Drop image here or click to upload</p>
</FileUpload>
);
}
ImagePreview
import { ImagePreview } from '@/plugins/file-storage/components';
<ImagePreview
src={user.avatarUrl}
alt={user.name}
width={100}
height={100}
fallback="/default-avatar.png"
/>;
Image Processing
Resize on Upload
import { uploadImage } from '@/plugins/file-storage';
const result = await uploadImage(file, {
folder: 'products',
resize: {
width: 800,
height: 600,
fit: 'cover'
},
formats: ['webp', 'jpg']
});
// result.variants: { webp: url, jpg: url }
Generate Thumbnails
const result = await uploadImage(file, {
folder: 'products',
thumbnails: [
{ name: 'small', width: 100, height: 100 },
{ name: 'medium', width: 400, height: 400 },
{ name: 'large', width: 800, height: 800 }
]
});
// result.thumbnails: { small: url, medium: url, large: url }
Security
Validation
import { validateFile } from '@/plugins/file-storage';
const validation = validateFile(file, {
maxSize: 10 * 1024 * 1024, // 10MB
allowedTypes: ['image/jpeg', 'image/png', 'application/pdf'],
allowedExtensions: ['.jpg', '.png', '.pdf']
});
if (!validation.valid) {
return Response.json({ error: validation.error }, { status: 400 });
}
Private Files
// Upload as private
await uploadFile(file, {
folder: 'private',
acl: 'private'
});
// Access with signed URL
const url = await getFileUrl('private/doc.pdf', {
signed: true,
expiresIn: 3600
});
API Routes
Upload Endpoint
app/api/upload/route.ts
import { NextResponse } from 'next/server';
import { uploadFile, validateFile } from '@/plugins/file-storage';
import { requireAuth } from '@/lib/auth';
export async function POST(request: Request) {
const user = await requireAuth(request);
const formData = await request.formData();
const file = formData.get('file') as File;
const validation = validateFile(file, {
maxSize: 5 * 1024 * 1024,
allowedTypes: ['image/*']
});
if (!validation.valid) {
return NextResponse.json({ error: validation.error }, { status: 400 });
}
const result = await uploadFile(file, {
folder: `users/${user.id}`,
generateUniqueName: true
});
return NextResponse.json(result);
}
Database Integration
File Model
model File {
id String @id @default(cuid())
key String @unique
filename String
contentType String
size Int
url String
userId String
user User @relation(fields: [userId], references: [id])
createdAt DateTime @default(now())
}
Track Uploads
const result = await uploadFile(file, { folder: 'documents' });
await prisma.file.create({
data: {
key: result.key,
filename: file.name,
contentType: file.type,
size: file.size,
url: result.url,
userId: user.id
}
});