# Storage — Features

> Global file storage with CDN distribution for Cloudflare Workers. Upload, retrieve, and delete files via the SDK. Backed by Cloudflare R2.

Aerostack Storage provides file uploads and object storage with global CDN distribution.

## Upload a file

### From the browser (React)

```tsx

function AvatarUpload({ userId }) {
  const { sdk } = useAerostack()

  const handleFile = async (e) => {
    const file = e.target.files[0]
    const formData = new FormData()
    formData.append('file', file)
    formData.append('path', `avatars/${userId}`)

    const result = await fetch(`/api/storage/upload`, {
      method: 'POST',
      headers: { Authorization: `Bearer ${tokens.accessToken}` },
      body: formData,
    })

    const { url } = await result.json()
    // url is the CDN URL for the uploaded file
  }

  return 
}
```

### From the server (Workers / Node.js)

```ts

// Upload from a request
app.post('/upload', async (c) => {
  const formData = await c.req.formData()
  const file = formData.get('file') as File

  const result = await sdk.storage.upload({
    file,
    path: `uploads/${Date.now()}-${file.name}`,
    contentType: file.type,
  })

  return c.json({ url: result.url, key: result.key })
})
```

## REST API

```bash
POST /api/v1/projects/{slug}/storage/upload
Content-Type: multipart/form-data
Authorization: Bearer {token}

# path: optional custom path (default: uuid)
```

**Response:**
```json
{
  "url": "https://cdn.aerostack.dev/projects/slug/uploads/file.jpg",
  "key": "projects/slug/uploads/file.jpg",
  "size": 204800,
  "contentType": "image/jpeg"
}
```

## Delete a file

```ts
await sdk.storage.delete('projects/slug/uploads/file.jpg')
```

## Supported file types

All file types are accepted. Maximum file size is **100 MB** per upload.

Files are stored in Aerostack's object storage and served via global CDN. Typical edge delivery latency is under 10ms worldwide.

## Use Cases

### User avatar uploads

Let users upload profile photos from any device. Store them at a predictable path like `avatars/{userId}` so you can always construct the CDN URL without a database lookup. Overwriting the same path replaces the old avatar automatically.

```ts
const result = await sdk.storage.upload({
  file,
  path: `avatars/${userId}`,
  contentType: 'image/jpeg',
})
// result.url is immediately available via CDN
```

### Document management system

Build a file manager where users upload, organize, and share PDFs, spreadsheets, and presentations. Use path prefixes like `docs/{orgId}/{folderId}/` to mirror your folder hierarchy in storage, and store metadata (file name, owner, permissions) in the database alongside the storage key.

### Media gallery

Accept image and video uploads for a portfolio, real estate listing, or social feed. Storage handles files up to 100 MB, so high-resolution images and short video clips work out of the box. Serve thumbnails and originals from the same CDN with different path conventions.

### CDN-backed static asset hosting

Host user-generated content (blog post images, community uploads, exported reports) with global CDN delivery. Since files are served from the edge, your users get sub-10ms latency regardless of their location.
