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

# Uploading images

> How to upload and manage images in Pindeck

# Uploading images

Upload images to Pindeck via drag-and-drop, file picker, or the Discord ingest pipeline.

## Upload workflow

1. Click **Upload** in the gallery or drag files onto the page
2. Files are stored in Convex file storage first
3. A background action persists the file to RustFS through the media API
4. Derivatives (preview, small, medium, large) are generated and stored alongside the original

### RustFS object path format

```
pindeck/media-uploads/YYYY/MM_DD/original/<filename>
pindeck/media-uploads/YYYY/MM_DD/preview/<filename>-preview.<ext>
pindeck/media-uploads/YYYY/MM_DD/low/<filename>-w320.webp
pindeck/media-uploads/YYYY/MM_DD/high/<filename>-w768.webp
pindeck/media-uploads/YYYY/MM_DD/high/<filename>-w1280.webp
```

Objects are written through the RustFS media API under the `pindeck` bucket.

## Image metadata

Every image record includes:

| Field           | Type                 | Description                                           |
| --------------- | -------------------- | ----------------------------------------------------- |
| `title`         | string               | Display name                                          |
| `description`   | string (optional)    | Detailed description                                  |
| `category`      | string               | Classification (Commercial, Film, Moodboard, etc.)    |
| `tags`          | string\[]            | Searchable keywords                                   |
| `group`         | string (optional)    | Project grouping (e.g., Commercial, Spec Music Video) |
| `projectName`   | string (optional)    | Specific project within a group                       |
| `projectOrder`  | number (optional)    | Sort order within a project                           |
| `moodboardName` | string (optional)    | Moodboard or reference name                           |
| `uniqueId`      | string (optional)    | Auto-generated or custom unique ID                    |
| `sourceType`    | string               | Origin: `upload`, `discord`, `pinterest`, `ai`        |
| `colors`        | string\[] (optional) | Extracted color palette                               |

## Persistence tracking

Each image tracks its durable storage status:

| Field                  | Values                           | Description                             |
| ---------------------- | -------------------------------- | --------------------------------------- |
| `storageProvider`      | `convex`, `rustfs`               | Where the file is currently stored      |
| `storageBucket`        | string                           | RustFS bucket name                      |
| `storagePersistStatus` | `pending`, `succeeded`, `failed` | Current persistence state               |
| `storagePersistError`  | string                           | Error message if persist failed         |
| `derivativeUrls`       | object                           | URLs for small/medium/large derivatives |

## Backfill failed uploads

Reschedule persistence for uploads stuck in Convex storage:

```bash theme={null}
bun run deploy:convex
```

This targets images where `sourceType = "upload"`, `storageProvider = "convex"`, and `storageId` is still present.

## Sources

Images can come from multiple sources:

* **Direct upload** — User-initiated from the gallery UI
* **Discord** — Ingested via the Discord bot emoji trigger (see [Discord bot](/guides/discord-bot))
* **Pinterest** — Imported from Pinterest boards
* **AI** — Generated as variations of existing images (see [AI generation](/guides/ai-generation))
