Storage

Easily set up file storage in your app with Cloudflare R2 or S3-compatible services to handle uploads, downloads, deletions, and public file access.

Tools

  • Cloudflare R2 – simple and cost-effective storage (recommended)
  • AWS S3 (or any S3-compatible service) – more advanced features

Setup

  1. Choose a storage provider:
    • Cloudflare R2 – recommended for simplicity and low cost
    • AWS S3 (or compatible services like MinIO, DigitalOcean Spaces, etc.)
  2. Create a bucket:
    • Go to your provider’s dashboard and create a new bucket (folder for files)
    • Copy the credentials: access key, secret key, bucket name, endpoint
  3. Cloudflare R2 specific steps:
    1. Sign up / Sign in at Cloudflare
    2. Create a new R2 bucket:
      • Pick a globally unique bucket name (e.g., your-project-name)
      • Select a region close to your target audience
    3. Enable public access: Settings → Public Development URL → Enable
      • Save the public URL as STORAGE_PUBLIC_URL
      • Optional: Set custom domains for added security
    4. Create a new API Token:
      • Storage & databases > R2 object storage > API Tokens > Manage, click Create User API Token
      • Set permissions to Object Read & Write to the bucket
      • Copy the Access Key ID and Secret Access Key
  4. Set the following environment variables:
    .env
    S3_REGION="your-region" # Use "auto" for R2, or e.g. "us-east-1" for S3
    S3_BUCKET="your-bucket-name"
    S3_ACCESS_KEY_ID="your-access-key-id"
    S3_SECRET_ACCESS_KEY="your-secret-access-key"
    S3_ENDPOINT="your-s3-endpoint" # Optional
    S3_PUBLIC_URL="https://cdn.yourdomain.com" # Public URL (CDN or subdomain)
    

Usage

Storage functions are available in the File Management module in the Admin Panel. Use the useApi composable:

  • List files:
    app/pages/admin/files.vue
    const { getStorageFiles } = useApi();
    const response = await getStorageFiles();
    console.log('File uploaded list:', response.data.blobs);
    
  • Upload files:
    app/pages/admin/files.vue
    const { uploadStorageFiles } = useApi();
    const selectedFiles = ref<File[]>([]);
    const response = await uploadStorageFiles(selectedFiles.value);
    console.log('File uploaded total:', response.data.success);
    
  • Download a File:
    app/pages/admin/files.vue
    const { downloadStorageFile } = useApi();
    const file = await downloadStorageFile('example.jpg');
    
  • Delete a File:
    app/pages/admin/files.vue
    const { deleteStorageFile } = useApi();
    const response = await deleteStorageFile('example.jpg');
    console.log('Deleted?', response.success);
    
  • Bulk delete files:
    app/pages/admin/files.vue
    const { bulkDeleteStorageFile } = useApi();
    const response = await bulkDeleteStorageFile(['example.jpg']);
    console.log('Deleted Total: ', response.data.success);
    
  • Access public file (CDN):
    app/pages/admin/files.vue
    const { public: pub } = useRuntimeConfig();
    const imageUrl = `${pub.storagePublicUrl}/example.jpg`;
    console.log(imageUrl); // https://cdn.yourdomain.com/example.jpg
    

Best Practices

  • File Size Limits: Set reasonable file size limits to prevent abuse
  • File Type Validation: Validate file types on both client and server sides for security