# How to Configure Media Storage, Archival, and Retrieval in Grok

> Configure media storage, archival, and retrieval in Grok using its three-layer subsystem. Learn about YAML drivers, metadata management, and HTTP endpoints for efficient media handling.

- Repository: [Chenyme/grok2api](https://github.com/chenyme/grok2api)
- Tags: how-to-guide
- Published: 2026-08-09

---

**Grok stores generated images and videos in a three-layer media subsystem that combines YAML-based storage drivers, database-backed metadata with automatic cleanup workers, and public HTTP endpoints for retrieval.**

The chenyme/grok2api repository implements a complete media management pipeline that allows operators to configure storage limits, enforce automatic archival policies, and serve assets through a public API. To configure media storage archival and retrieval in Grok, administrators modify the `media` section of the configuration file and tune runtime parameters through the admin settings interface.

## Media Configuration and Storage Drivers

### YAML Configuration Structure

All storage parameters reside under the top-level `media:` key in [`config.example.yaml`](https://github.com/chenyme/grok2api/blob/main/config.example.yaml) (lines 80-87). Currently, only the **local** driver is supported, which writes raw image and video files to a specified directory.

```yaml
media:
  driver: local                     # only "local" is supported now

  local:
    path: "./data/media"           # directory where raw files are written

```

### Runtime Limits and Admin UI

The admin interface (accessed at `/settings`) exposes additional runtime constraints managed by [`frontend/src/features/settings/settings-model.ts`](https://github.com/chenyme/grok2api/blob/main/frontend/src/features/settings/settings-model.ts). These values are persisted in the `media_config` database table and exposed via the `/api/admin/v1/settings` endpoint:

- **`maxImageBytes`** – Maximum size of a single image file (default: 32 MiB)
- **`maxTotalBytes`** – Total storage quota for all media assets (default: 1 GiB)
- **`cleanupThresholdPercent`** – Storage usage percentage that triggers automatic deletion of oldest assets (default: 80%)
- **`cleanupInterval`** – Frequency of background cleanup checks (default: `1m`)
- **`publicApiBaseURL`** – Base URL used to generate public-facing asset links (auto-derived from server address if not set)

## The Archival and Cleanup Workflow

### Size Accounting and Triggers

Every time an image or video is saved, the service updates a bytes-used counter stored in the database. The `checkCapacity` function in [`backend/internal/application/media/service.go`](https://github.com/chenyme/grok2api/blob/main/backend/internal/application/media/service.go) enforces the `maxImageBytes` limit on individual uploads and tracks aggregate usage against `maxTotalBytes`.

When used storage exceeds `maxTotalBytes * cleanupThresholdPercent/100`, the service triggers automatic archival.

### The Cleanup Worker

The `cleanupWorker` goroutine, scheduled by the `Start` method in [`backend/internal/application/media/service.go`](https://github.com/chenyme/grok2api/blob/main/backend/internal/application/media/service.go), periodically executes `runCleanup` from [`backend/internal/application/media/cleanup.go`](https://github.com/chenyme/grok2api/blob/main/backend/internal/application/media/cleanup.go) based on the configured `cleanupInterval`.

The worker performs the following steps:

1. Queries the `media_asset` table ordered by creation time (oldest first)
2. Deletes physical files from the `media.local.path` directory
3. Removes database records until usage falls below the threshold
4. Invalidates existing public URLs (subsequent requests return **404** with error code `mediaAssetNotFound`)

## Media Retrieval via Public API

Assets are served through read-only endpoints registered in [`backend/internal/transport/http/media/handler.go`](https://github.com/chenyme/grok2api/blob/main/backend/internal/transport/http/media/handler.go) (lines 28-31). These handlers delegate to `service.GetImage` and `service.GetVideo`, which verify file existence on disk and stream content with proper `Content-Type` headers.

| Endpoint | Method | Description |
|----------|--------|-------------|
| `GET /v1/media/images/:assetId` | Public | Returns the raw image file or `b64_json` payload |
| `GET /v1/media/videos/:assetId` | Public | Streams the video file or returns a temporary URL |

When an asset is missing—either because it was deleted by the cleanup worker or manually removed—the API returns a **404 Not Found** status.

## Upload Flow and Size Enforcement

Admin clients ingest media through authenticated endpoints implemented in [`backend/internal/transport/http/media/ingest.go`](https://github.com/chenyme/grok2api/blob/main/backend/internal/transport/http/media/ingest.go). These handlers enforce the `maxImageBytes` limit before storage:

| Endpoint | Purpose |
|----------|---------|
| `POST /api/admin/v1/media/inputs/upload` | Direct multipart upload via `uploadInputImage` |
| `POST /api/admin/v1/media/inputs/import` | Import from external URL via `importInputImageFromURL` |

Both functions return a `MediaInputDTO` containing the generated asset ID and its public URL. You can force an immediate cleanup run via the admin endpoint `POST /api/admin/v1/media/cleanup`.

## Summary

- **Configuration** happens in [`config.example.yaml`](https://github.com/chenyme/grok2api/blob/main/config.example.yaml) under the `media:` key, with runtime limits adjustable through the `/settings` UI and stored in the `media_config` table.
- **Archival** is handled automatically by a background worker in [`backend/internal/application/media/cleanup.go`](https://github.com/chenyme/grok2api/blob/main/backend/internal/application/media/cleanup.go) that deletes oldest assets when usage exceeds `cleanupThresholdPercent`.
- **Retrieval** occurs through public endpoints at `/v1/media/images/:assetId` and `/v1/media/videos/:assetId`, returning 404 for cleaned assets.
- **Uploads** are processed by [`backend/internal/transport/http/media/ingest.go`](https://github.com/chenyme/grok2api/blob/main/backend/internal/transport/http/media/ingest.go), which enforces `maxImageBytes` and stores metadata in `media_asset`.

## Frequently Asked Questions

### What storage drivers does Grok support for media?

Currently, only the **local** driver is implemented. According to [`config.example.yaml`](https://github.com/chenyme/grok2api/blob/main/config.example.yaml), you must specify `driver: local` and provide a filesystem path via `media.local.path`. The architecture in [`backend/internal/application/media/service.go`](https://github.com/chenyme/grok2api/blob/main/backend/internal/application/media/service.go) supports future driver extensions, but no cloud or object storage backends are available in the current codebase.

### How does Grok handle storage quota exceeded scenarios?

When the aggregate size of stored assets exceeds `maxTotalBytes * cleanupThresholdPercent/100`, the `cleanupWorker` goroutine automatically deletes the oldest assets from the `media_asset` table and removes corresponding files from `media.local.path`. This process runs every `cleanupInterval` (default one minute) to ensure total storage remains bounded.

### Can I manually trigger media cleanup?

Yes. Administrators can force an immediate cleanup run by sending a `POST` request to `/api/admin/v1/media/cleanup`. This bypasses the normal interval and executes the same `runCleanup` logic found in [`backend/internal/application/media/cleanup.go`](https://github.com/chenyme/grok2api/blob/main/backend/internal/application/media/cleanup.go), deleting assets until usage falls below the threshold.

### What happens to public URLs when media is deleted?

Public URLs become invalid immediately upon deletion. When a client requests `GET /v1/media/images/:assetId` or `GET /v1/media/videos/:assetId`, the handler in [`backend/internal/transport/http/media/handler.go`](https://github.com/chenyme/grok2api/blob/main/backend/internal/transport/http/media/handler.go) checks the `media_asset` table and filesystem. If the asset is missing, the API returns **404 Not Found** with the error code `mediaAssetNotFound`.