> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cocobase.cc/llms.txt
> Use this file to discover all available pages before exploring further.

# File Storage

> Upload and manage files within documents and user profiles

# File Storage

Upload files as part of your documents and user profiles with automatic S3 storage integration. Files are uploaded alongside your data and their URLs are automatically stored in your documents.

<Note>
  Cocobase integrates file uploads directly into document and user operations. Files are automatically uploaded to S3 storage and their URLs are saved in your documents.
</Note>

## Overview

File storage features:

* **Integrated uploads** - Upload files with document creation/updates
* **Multiple file types** - Images, documents, videos, any file type
* **Single or array** - Upload single files or arrays of files
* **Automatic URLs** - File URLs automatically saved in documents
* **S3 storage** - Secure, scalable cloud storage
* **User profile files** - Upload avatars and cover photos with registration

***

## Upload Files with Documents

Upload files when creating or updating documents using field naming.

### Single File Upload

<Tabs>
  <Tab title="JavaScript">
    ```javascript theme={null}

    import { Cocobase } from 'cocobase';

    const db = new Cocobase({ apiKey: 'your-api-key' });

    const user = await db.createDocumentWithFiles(
      'users',
      {
        name: 'John Doe',
        email: 'john@example.com',
        bio: 'Software developer'
      },
      {
        avatar: avatarFile,
        cover_photo: coverPhotoFile
      }
    );

    console.log('Avatar URL:', user.data.avatar);
    console.log('Cover URL:', user.data.cover_photo);
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    import { Cocobase } from 'cocobase';

    interface UserData {
      name: string;
      email: string;
      bio: string;
    }

    const db = new Cocobase({ apiKey: 'your-api-key' });

    // Type-safe file upload
    const user = await db.createDocumentWithFiles<UserData>(
      'users',
      {
        name: 'John Doe',
        email: 'john@example.com',
        bio: 'Software developer'
      },
      {
        avatar: avatarFile,
        cover_photo: coverPhotoFile
      }
    );

    // user.data.avatar is a string URL
    console.log('Avatar URL:', user.data.avatar);
    ```
  </Tab>

  <Tab title="Dart">
    ```dart theme={null}
    import 'package:coco_base_flutter/coco_base_flutter.dart';
    import 'dart:io';

    final db = Cocobase(CocobaseConfig(apiKey: 'your-api-key'));

    // Get file from file picker
    final avatarFile = File('/path/to/avatar.jpg');
    final coverFile = File('/path/to/cover.jpg');

    // Upload files with document
    final user = await db.createDocumentWithFiles(
      'users',
      {
        'name': 'John Doe',
        'email': 'john@example.com',
        'bio': 'Software developer'
      },
      {
        'avatar': avatarFile,
        'cover_photo': coverFile
      }
    );

    print('Avatar URL: ${user.data['avatar']}');
    print('Cover URL: ${user.data['cover_photo']}');
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    from cocobase import Cocobase

    db = Cocobase(api_key='your-api-key')

    # Upload file with document
    with open('/path/to/avatar.jpg', 'rb') as avatar_file, \
         open('/path/to/cover.jpg', 'rb') as cover_file:

        user = db.create_document_with_files(
            'users',
            {
                'name': 'John Doe',
                'email': 'john@example.com',
                'bio': 'Software developer'
            },
            {
                'avatar': avatar_file,
                'cover_photo': cover_file
            }
        )

    print(f"Avatar URL: {user['data']['avatar']}")
    print(f"Cover URL: {user['data']['cover_photo']}")
    ```
  </Tab>
</Tabs>

**Response Structure:**

```json theme={null}
{
  "id": "user-123",
  "collection": "users",
  "createdAt": "2024-01-15T10:30:00Z",
  "updatedAt": "2024-01-15T10:30:00Z",
  "data": {
    "name": "John Doe",
    "email": "john@example.com",
    "bio": "Software developer",
    "avatar": "https://storage.cocobase.cc/.../avatar.jpg",
    "cover_photo": "https://storage.cocobase.cc/.../cover.jpg"
  }
}
```

### Multiple Files (Array)

Upload multiple files to create an array of URLs:

<Tabs>
  <Tab title="JavaScript">
    ```javascript theme={null}
    const product = await db.createDocumentWithFiles(
      'products',
      {
        name: 'Laptop',
        price: 1299,
        description: 'High-performance laptop'
      },
      {
        main_image: mainImageFile,
        gallery: [img1File, img2File, img3File]
      }
    );

    console.log('Main image:', product.data.main_image);
    console.log('Gallery:', product.data.gallery);
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    interface ProductData {
      name: string;
      price: number;
      description: string;
    }

    const product = await db.createDocumentWithFiles<ProductData>(
      'products',
      {
        name: 'Laptop',
        price: 1299,
        description: 'High-performance laptop'
      },
      {
        main_image: mainImageFile,
        gallery: [img1File, img2File, img3File]
      }
    );

    // Type-safe access
    const imageUrl: string = product.data.main_image;
    const galleryUrls: string[] = product.data.gallery;
    ```
  </Tab>

  <Tab title="Dart">
    ```dart theme={null}
    // Product with multiple images
    final images = [
      File('/path/to/img1.jpg'),
      File('/path/to/img2.jpg'),
      File('/path/to/img3.jpg')
    ];

    final product = await db.createDocumentWithFiles(
      'products',
      {
        'name': 'Laptop',
        'price': 1299,
        'description': 'High-performance laptop'
      },
      {
        'main_image': File('/path/to/main.jpg'),
        'gallery': images
      }
    );

    print('Gallery URLs: ${product.data['gallery']}');
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    # Product with gallery
    with open('/path/to/main.jpg', 'rb') as main, \
         open('/path/to/img1.jpg', 'rb') as img1, \
         open('/path/to/img2.jpg', 'rb') as img2, \
         open('/path/to/img3.jpg', 'rb') as img3:

        product = db.create_document_with_files(
            'products',
            {
                'name': 'Laptop',
                'price': 1299,
                'description': 'High-performance laptop'
            },
            {
                'main_image': main,
                'gallery': [img1, img2, img3]
            }
        )

    print(f"Gallery: {product['data']['gallery']}")
    ```
  </Tab>
</Tabs>

**Response:**

```json theme={null}
{
  "id": "product-123",
  "data": {
    "name": "Laptop",
    "price": 1299,
    "description": "High-performance laptop",
    "main_image": "https://storage.cocobase.cc/.../main.jpg",
    "gallery": [
      "https://storage.cocobase.cc/.../img1.jpg",
      "https://storage.cocobase.cc/.../img2.jpg",
      "https://storage.cocobase.cc/.../img3.jpg"
    ]
  }
}
```

***

## Update Documents with Files

Update existing documents with new files:

<Tabs>
  <Tab title="JavaScript">
    ```javascript theme={null}
    // Update only the avatar
    await db.updateDocumentWithFiles(
      'users',
      'user-123',
      undefined,  // No data changes
      { avatar: newAvatarFile }
    );

    // Update both data and files
    await db.updateDocumentWithFiles(
      'users',
      'user-123',
      { bio: 'Updated bio' },
      { avatar: newAvatarFile, cover_photo: newCoverFile }
    );
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    // Type-safe update
    await db.updateDocumentWithFiles<UserData>(
      'users',
      'user-123',
      { bio: 'Updated bio' },
      { avatar: newAvatarFile }
    );
    ```
  </Tab>

  <Tab title="Dart">
    ```dart theme={null}
    // Update files only
    await db.updateDocumentWithFiles(
      'users',
      'user-123',
      null,  // No data updates
      {
        'avatar': File('/path/to/new-avatar.jpg')
      }
    );

    // Update data and files
    await db.updateDocumentWithFiles(
      'users',
      'user-123',
      {'bio': 'Updated bio'},
      {'avatar': File('/path/to/new-avatar.jpg')}
    );
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    # Update files
    with open('/path/to/new-avatar.jpg', 'rb') as avatar:
        db.update_document_with_files(
            'users',
            'user-123',
            None,  # No data updates
            {'avatar': avatar}
        )

    # Update data and files
    with open('/path/to/new-avatar.jpg', 'rb') as avatar:
        db.update_document_with_files(
            'users',
            'user-123',
            {'bio': 'Updated bio'},
            {'avatar': avatar}
        )
    ```
  </Tab>
</Tabs>

***

## User Registration with Files

Register users with profile pictures:

<Tabs>
  <Tab title="JavaScript">
    ```javascript theme={null}
    await db.registerWithFiles(
      'john@example.com',
      'password123',
      {
        username: 'johndoe',
        full_name: 'John Doe',
        bio: 'Developer'
      },
      { avatar: avatarFile }
    );

    const user = await db.auth.getUser();
    console.log('Avatar URL:', user.avatar);
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    interface UserMetadata {
      username: string;
      full_name: string;
      bio?: string;
    }

    // Type-safe registration
    await db.registerWithFiles<UserMetadata>(
      'john@example.com',
      'password123',
      {
        username: 'johndoe',
        full_name: 'John Doe',
        bio: 'Developer'
      },
      {
        avatar: avatarFile,
        cover_photo: coverFile
      }
    );

    const user = await db.auth.getUser();
    // user.avatar is a string URL
    ```
  </Tab>

  <Tab title="Dart">
    ```dart theme={null}
    // Note: File uploads during registration are not yet supported in the Flutter SDK.
    await db.register(
      email: 'john@example.com',
      password: 'password123',
      data: {
        'username': 'johndoe',
        'full_name': 'John Doe',
        'bio': 'Developer'
      },
    );

    // Get user
    final user = await db.getCurrentUser();
    print('Avatar: ${user?.data['avatar']}');
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    # Register with avatar
    with open('/path/to/avatar.jpg', 'rb') as avatar:
        db.auth.register_with_files(
            'john@example.com',
            'password123',
            {
                'username': 'johndoe',
                'full_name': 'John Doe',
                'bio': 'Developer'
            },
            {
                'avatar': avatar
            }
        )

    # Get user
    user = db.auth.get_user()
    print(f"Avatar: {user['avatar']}")
    ```
  </Tab>
</Tabs>

**Response:**

```json theme={null}
{
  "id": "user-123",
  "email": "john@example.com",
  "username": "johndoe",
  "full_name": "John Doe",
  "bio": "Developer",
  "avatar": "https://storage.cocobase.cc/.../avatar.jpg",
  "createdAt": "2024-01-15T10:00:00Z"
}
```

***

## Update User Profile with Files

Update authenticated user's profile pictures:

<Tabs>
  <Tab title="JavaScript">
    ```javascript theme={null}
    // Update avatar only
    await db.updateUserWithFiles(undefined, undefined, undefined, { avatar: newAvatarFile });

    // Update bio and avatar
    await db.updateUserWithFiles({ bio: 'Updated bio', location: 'New York' }, undefined, undefined, { avatar: newAvatarFile });

    // Update email, data, and files
    await db.updateUserWithFiles(
      { username: 'newusername' },
      'newemail@example.com',
      undefined,
      {
        avatar: newAvatar,
        cover_photo: newCover
      }
    );
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={null}
    // Type-safe user update
    await db.updateUserWithFiles<UserMetadata>(
      { bio: 'Updated bio' },
      undefined,
      undefined,
      { avatar: newAvatarFile }
    );
    ```
  </Tab>

  <Tab title="Dart">
    ```dart theme={null}
    // Note: File uploads during user update use db.updateUser() in the Flutter SDK.
    // Update user avatar
    await db.updateUser(
      data: {'bio': 'Updated bio'},
      files: {'avatar': File('/path/to/new-avatar.jpg')}
    );

    // Update multiple fields
    await db.updateUser(
      data: {'bio': 'Updated bio', 'location': 'New York'},
      email: 'newemail@example.com',
      files: {
        'avatar': File('/path/to/avatar.jpg'),
        'cover_photo': File('/path/to/cover.jpg')
      }
    );
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    # Update user avatar
    with open('/path/to/new-avatar.jpg', 'rb') as avatar:
        db.auth.update_user_with_files(
            data={'bio': 'Updated bio'},
            files={'avatar': avatar}
        )

    # Update multiple fields
    with open('/path/to/avatar.jpg', 'rb') as avatar, \
         open('/path/to/cover.jpg', 'rb') as cover:
        db.auth.update_user_with_files(
            data={'bio': 'Updated', 'location': 'New York'},
            email='newemail@example.com',
            files={
                'avatar': avatar,
                'cover_photo': cover
            }
        )
    ```
  </Tab>
</Tabs>

***

## React Example

Complete React component with file uploads:

```tsx theme={null}
import React, { useState } from 'react';
import { Cocobase } from 'cocobase';

const db = new Cocobase({ apiKey: 'your-api-key' });

function SignUpForm() {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [username, setUsername] = useState('');
  const [avatarFile, setAvatarFile] = useState<File | null>(null);
  const [avatarPreview, setAvatarPreview] = useState<string | null>(null);
  const [loading, setLoading] = useState(false);

  const handleAvatarChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (file) {
      // Validate file
      if (!['image/jpeg', 'image/png', 'image/webp'].includes(file.type)) {
        alert('Please upload a valid image file');
        return;
      }

      if (file.size > 5 * 1024 * 1024) { // 5MB
        alert('File size must be less than 5MB');
        return;
      }

      setAvatarFile(file);

      // Show preview
      const reader = new FileReader();
      reader.onloadend = () => {
        setAvatarPreview(reader.result as string);
      };
      reader.readAsDataURL(file);
    }
  };

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setLoading(true);

    try {
      await db.registerWithFiles(
        email,
        password,
        { username },
        avatarFile ? { avatar: avatarFile } : undefined
      );

      // Get user details
      const user = await db.auth.getUser();
      console.log('User created:', user);
      alert('Sign up successful!');
    } catch (error) {
      console.error('Sign up failed:', error);
      alert('Sign up failed. Please try again.');
    } finally {
      setLoading(false);
    }
  };

  return (
    <div className="max-w-md mx-auto p-6">
      <h2 className="text-2xl font-bold mb-6">Create Your Account</h2>

      <form onSubmit={handleSubmit} className="space-y-4">
        {/* Avatar Preview */}
        {avatarPreview && (
          <div className="flex justify-center mb-4">
            <img
              src={avatarPreview}
              alt="Avatar preview"
              className="w-24 h-24 rounded-full object-cover"
            />
          </div>
        )}

        {/* Avatar Upload */}
        <div>
          <label className="block text-sm font-medium mb-2">
            Profile Picture
          </label>
          <input
            type="file"
            accept="image/*"
            onChange={handleAvatarChange}
            className="w-full"
          />
        </div>

        <input
          type="text"
          placeholder="Username"
          value={username}
          onChange={(e) => setUsername(e.target.value)}
          required
          className="w-full px-3 py-2 border rounded"
        />

        <input
          type="email"
          placeholder="Email"
          value={email}
          onChange={(e) => setEmail(e.target.value)}
          required
          className="w-full px-3 py-2 border rounded"
        />

        <input
          type="password"
          placeholder="Password"
          value={password}
          onChange={(e) => setPassword(e.target.value)}
          required
          className="w-full px-3 py-2 border rounded"
        />

        <button
          type="submit"
          disabled={loading}
          className="w-full bg-blue-600 text-white py-2 rounded hover:bg-blue-700 disabled:bg-gray-400"
        >
          {loading ? 'Creating Account...' : 'Sign Up'}
        </button>
      </form>
    </div>
  );
}
```

***

## Product Gallery Example

Create products with multiple images:

```tsx theme={null}
import React, { useState } from 'react';
import { Cocobase } from 'cocobase';

const db = new Cocobase({ apiKey: 'your-api-key' });

function CreateProductForm() {
  const [name, setName] = useState('');
  const [price, setPrice] = useState('');
  const [mainImage, setMainImage] = useState<File | null>(null);
  const [galleryImages, setGalleryImages] = useState<File[]>([]);
  const [loading, setLoading] = useState(false);

  const handleGalleryChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const files = Array.from(e.target.files || []);
    setGalleryImages(files);
  };

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setLoading(true);

    try {
      const files: Record<string, File | File[]> = {};

      if (mainImage) {
        files.main_image = mainImage;
      }

      if (galleryImages.length > 0) {
        files.gallery = galleryImages;
      }

      const product = await db.createDocumentWithFiles(
        'products',
        {
          name,
          price: parseFloat(price),
          status: 'active'
        },
        files
      );

      console.log('Product created:', product);
      alert('Product created successfully!');

      // Reset form
      setName('');
      setPrice('');
      setMainImage(null);
      setGalleryImages([]);
    } catch (error) {
      console.error('Product creation failed:', error);
      alert('Failed to create product');
    } finally {
      setLoading(false);
    }
  };

  return (
    <form onSubmit={handleSubmit} className="space-y-4">
      <h2 className="text-2xl font-bold">Create Product</h2>

      <input
        type="text"
        placeholder="Product Name"
        value={name}
        onChange={(e) => setName(e.target.value)}
        required
        className="w-full px-3 py-2 border rounded"
      />

      <input
        type="number"
        placeholder="Price"
        value={price}
        onChange={(e) => setPrice(e.target.value)}
        required
        step="0.01"
        className="w-full px-3 py-2 border rounded"
      />

      <div>
        <label className="block text-sm font-medium mb-2">Main Image</label>
        <input
          type="file"
          accept="image/*"
          onChange={(e) => setMainImage(e.target.files?.[0] || null)}
          className="w-full"
        />
      </div>

      <div>
        <label className="block text-sm font-medium mb-2">
          Gallery Images (Multiple)
        </label>
        <input
          type="file"
          accept="image/*"
          multiple
          onChange={handleGalleryChange}
          className="w-full"
        />
        {galleryImages.length > 0 && (
          <p className="text-sm text-gray-600 mt-1">
            {galleryImages.length} image(s) selected
          </p>
        )}
      </div>

      <button
        type="submit"
        disabled={loading}
        className="w-full bg-blue-600 text-white py-2 rounded hover:bg-blue-700 disabled:bg-gray-400"
      >
        {loading ? 'Creating...' : 'Create Product'}
      </button>
    </form>
  );
}
```

***

## Best Practices

<AccordionGroup>
  <Accordion title="Validate Files Before Upload">
    Always validate file types and sizes before uploading:

    ```typescript theme={null}
    const validateImage = (file: File): boolean => {
      const validTypes = ['image/jpeg', 'image/png', 'image/webp', 'image/gif'];
      const maxSize = 5 * 1024 * 1024; // 5MB

      if (!validTypes.includes(file.type)) {
        alert('Please upload a valid image file');
        return false;
      }

      if (file.size > maxSize) {
        alert('File size must be less than 5MB');
        return false;
      }

      return true;
    };
    ```
  </Accordion>

  <Accordion title="Show Upload Progress">
    Provide visual feedback during uploads:

    ```typescript theme={null}
    const [loading, setLoading] = useState(false);

    const handleUpload = async () => {
      setLoading(true);
      try {
        await db.createDocumentWithFiles(/* ... */);
      } finally {
        setLoading(false);
      }
    };
    ```
  </Accordion>

  <Accordion title="Compress Images">
    Reduce file sizes before uploading:

    ```typescript theme={null}
    import imageCompression from 'browser-image-compression';

    const compressImage = async (file: File): Promise<File> => {
      const options = {
        maxSizeMB: 1,
        maxWidthOrHeight: 1920,
        useWebWorker: true
      };
      return await imageCompression(file, options);
    };

    // Use compressed image
    const compressed = await compressImage(originalFile);
    await db.createDocumentWithFiles('users', data, { avatar: compressed });
    ```
  </Accordion>

  <Accordion title="Show Image Previews">
    Let users preview images before uploading:

    ```typescript theme={null}
    const [preview, setPreview] = useState<string | null>(null);

    const handleFileChange = (file: File) => {
      const reader = new FileReader();
      reader.onloadend = () => {
        setPreview(reader.result as string);
      };
      reader.readAsDataURL(file);
    };
    ```
  </Accordion>

  <Accordion title="Handle Errors Gracefully">
    Provide meaningful error messages:

    ```typescript theme={null}
    try {
      await db.createDocumentWithFiles(/* ... */);
    } catch (error) {
      if (error.message.includes('Storage limit')) {
        alert('Storage limit exceeded. Please upgrade your plan.');
      } else if (error.message.includes('Invalid file')) {
        alert('Invalid file format. Please use JPG, PNG, or WebP.');
      } else {
        alert('Upload failed. Please try again.');
      }
    }
    ```
  </Accordion>
</AccordionGroup>

***

## Field Naming Convention

Use descriptive field names for your files:

```typescript theme={null}
// User profiles
{ avatar: file, cover_photo: file, profile_picture: file }

// Products
{ main_image: file, thumbnail: file, gallery: [files] }

// Blog posts
{ featured_image: file, inline_images: [files] }

// Documents
{ id_document: file, verification_photo: file }

// Real estate
{ main_photo: file, photos: [files], floor_plan: file }
```

***

## File Limits

| Limit Type          | Value          |
| ------------------- | -------------- |
| Maximum file size   | 50 MB          |
| Supported formats   | All file types |
| Files per request   | 10 files       |
| Storage per project | Based on plan  |

***

## Common Use Cases

### User Avatars

```typescript theme={null}
await db.registerWithFiles(
  email,
  password,
  { username },
  { avatar: avatarFile }
);
```

### Product Images

```typescript theme={null}
await db.createDocumentWithFiles(
  'products',
  { name, price },
  { main_image: mainFile, gallery: [img1, img2, img3] }
);
```

### Document Uploads

```typescript theme={null}
await db.createDocumentWithFiles(
  'applications',
  { applicant_name, status },
  { resume: resumePdf, cover_letter: coverPdf }
);
```

### Blog Post Media

```typescript theme={null}
await db.createDocumentWithFiles(
  'posts',
  { title, content },
  { featured_image: featuredFile, attachments: [file1, file2] }
);
```

***

## Next Steps

<CardGroup cols={2}>
  <Card title="CRUD Operations" icon="database" href="/features/crud-operations">
    Learn about creating and updating documents
  </Card>

  <Card title="Authentication" icon="lock" href="/core-concepts/authentication">
    User authentication with profile pictures
  </Card>

  <Card title="Data Types" icon="code" href="/core-concepts/data-types">
    Understanding data structures
  </Card>

  <Card title="Best Practices" icon="star" href="/guides/best-practices">
    Tips for optimal file handling
  </Card>
</CardGroup>
