# Storage — SDK

> Upload files, get CDN URLs, manage metadata, copy and move objects with the Aerostack Storage SDK.

The Storage module provides file upload, CDN-backed URLs, metadata management, and file operations (copy, move, delete). Files are stored with global CDN distribution.

  **Beta** -- Storage APIs are stable but may receive non-breaking additions.

## What you can build

- **User avatars** -- Upload profile pictures with automatic CDN URLs
- **Document management** -- Store and organize PDFs, spreadsheets, and text files
- **Media galleries** -- Image and video upload with metadata (dimensions, MIME type)
- **File attachments** -- Attach files to chat messages, support tickets, or form submissions
- **Backup exports** -- Generate and store data export files for users to download

## Upload a file

  
```ts
const result = await sdk.storage.upload({
  file: fileBlob,                // File, Blob, or ReadableStream
  path: 'avatars/user-123.jpg', // Optional custom path
  contentType: 'image/jpeg',    // Optional MIME type
})

console.log(result.url)         // CDN URL: https://cdn.aerostack.dev/proj_abc123/avatars/user-123.jpg
console.log(result.key)         // Storage key: avatars/user-123.jpg
console.log(result.size)        // File size in bytes
console.log(result.contentType) // image/jpeg
```
  
  
```go
result, err := client.Storage.Upload(ctx, aerostack.UploadInput{
    File:        reader,
    Path:        "avatars/user-123.jpg",
    ContentType: "image/jpeg",
})
// result.URL, result.Key, result.Size
```
  
  
```python
result = await client.storage.upload(
    file_bytes=image_data,
    path="avatars/user-123.jpg",
    content_type="image/jpeg"
)
# result.url, result.key
```
  
  
```dart
final file = File('/path/to/image.jpg');
final result = await client.storage.upload(
  file: file,
  path: 'avatars/${userId}.jpg',
  contentType: 'image/jpeg',
);
final cdnUrl = result.url;
```
  

---

## Get a file

Retrieve file content by its storage key:

```ts
const file = await sdk.storage.get('avatars/user-123.jpg')
// Returns the file content
```

## Get a CDN URL

Get a public CDN URL for a stored file without downloading it:

```ts
const url = await sdk.storage.getUrl('avatars/user-123.jpg')
// https://cdn.aerostack.dev/proj_abc123/avatars/user-123.jpg
```

## List files

```ts
const files = await sdk.storage.list({
  prefix: 'avatars/',   // Filter by path prefix
  limit: 50,            // Max results
})
// files: [{ key, size, contentType, lastModified }, ...]
```

## Check if a file exists

```ts
const exists = await sdk.storage.exists('avatars/user-123.jpg')
// true or false
```

## Get file metadata

```ts
const meta = await sdk.storage.getMetadata('avatars/user-123.jpg')
// { key, size, contentType, lastModified, etag }
```

## Copy a file

```ts
await sdk.storage.copy('avatars/user-123.jpg', 'backups/user-123.jpg')
```

## Move a file

```ts
await sdk.storage.move('uploads/temp-abc.jpg', 'avatars/user-123.jpg')
// Original file is deleted after copy
```

## Delete a file

```ts
await sdk.storage.delete('avatars/user-123.jpg')
```

---

## Complete example: avatar upload system

```ts title="avatar-upload.ts"

const { sdk } = new AerostackClient({ projectId, apiKey })

async function uploadAvatar(userId: string, file: File) {
  // 1. Upload the new avatar
  const result = await sdk.storage.upload({
    file,
    path: `avatars/${userId}.${file.type.split('/')[1]}`,
    contentType: file.type,
  })

  // 2. Update the user profile with the new URL
  await sdk.db.query(
    'UPDATE users SET avatar_url = ?, updated_at = ? WHERE id = ?',
    [result.url, Date.now(), userId]
  )

  return result.url
}

async function deleteAvatar(userId: string) {
  // 1. Get current avatar path
  const user = await sdk.db.queryOne(
    'SELECT avatar_url FROM users WHERE id = ?',
    [userId]
  )

  if (user?.avatar_url) {
    // 2. Extract key from URL and delete
    const key = user.avatar_url.split('/').slice(-2).join('/')
    await sdk.storage.delete(key)
  }

  // 3. Clear the profile
  await sdk.db.query(
    'UPDATE users SET avatar_url = NULL, updated_at = ? WHERE id = ?',
    [Date.now(), userId]
  )
}
```

---

## Complete example: document manager

```ts title="documents.ts"
async function uploadDocument(userId: string, file: File, folder: string) {
  const id = crypto.randomUUID()
  const ext = file.name.split('.').pop()

  // Upload to storage
  const result = await sdk.storage.upload({
    file,
    path: `documents/${userId}/${folder}/${id}.${ext}`,
    contentType: file.type,
  })

  // Record in database
  const { results: [doc] } = await sdk.db.query(
    `INSERT INTO documents (id, user_id, folder, filename, storage_key, url, size, content_type, created_at)
     VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING *`,
    [id, userId, folder, file.name, result.key, result.url, result.size, result.contentType, Date.now()]
  )

  return doc
}

async function listDocuments(userId: string, folder: string) {
  const { results } = await sdk.db.query(
    'SELECT * FROM documents WHERE user_id = ? AND folder = ? ORDER BY created_at DESC',
    [userId, folder]
  )
  return results
}
```

---

## API reference

| Method | Signature | Returns |
|--------|-----------|---------|
| `sdk.storage.upload` | `(opts: { file, path?, contentType? }) => Promise` | `{ url, key, size, contentType }` |
| `sdk.storage.get` | `(key: string) => Promise<any>` | File content |
| `sdk.storage.getUrl` | `(key: string) => Promise<string>` | CDN URL |
| `sdk.storage.list` | `(opts?: { prefix?, limit? }) => Promise` | Array of file info |
| `sdk.storage.delete` | `(key: string) => Promise<void>` | Nothing |
| `sdk.storage.exists` | `(key: string) => Promise<boolean>` | Boolean |
| `sdk.storage.getMetadata` | `(key: string) => Promise` | Metadata object |
| `sdk.storage.copy` | `(source: string, dest: string) => Promise<void>` | Nothing |
| `sdk.storage.move` | `(source: string, dest: string) => Promise<void>` | Nothing |
