Features Apograph CMS on GitHub

The media library

Media plugin @apograph/media-server@apograph/media-admin

Where assets live, how they get there, and how they attach to a record.

Documents 0.5.2 Updated Edit this page Report a problem

On this page

Each workspace has its own media library, at Media in the workspace sidebar. Assets belong to the workspace and never cross between them.

Browsing

A folder tree on the left — headed by All media, with a new-folder action and a storage meter — and a grid of assets on the right. Images render their real preview; other kinds get a glyph.

The toolbar has a search box (matching name and tags), a type filter, and a sort control.

Uploading

The upload dialog takes multiple files by drag-and-drop or a picker, and accumulates across drops. Files are staged first — images with a real local thumbnail — so you can see what you are about to send and remove anything you did not mean to include.

Confirming closes the dialog and hands the files to a queue that uploads at most three at a time, one request per file, driving a progress banner above the browser with a bar per file, retry on failure, and cancel while in flight.

One request per file matters: a single batched request loses the whole batch to one rejection.

There is no upload success toast

The dialog closes on submit, and the upload has not happened yet at that point. The banner is the status surface — a toast fired at submit time would be claiming a result that had not occurred, which is how “Uploaded 12 files” ends up on screen beside a failure.

Alt text

Alt text is writable in exactly two places:

  • Per staged image in the upload dialog, before it is sent.
  • In the asset detail drawer, for anyone with media:update.

Neither blocks anything: skipping alt uploads exactly as before, and a blank value is never sent. But the Insights dashboard has an alt-coverage card that counts undescribed images, so it is visible when a library drifts.

An unattended import over the API should pass ?alt= — see the media API.

Actions

ScopeAvailable
Per assetDownload, copy link, duplicate, rename, move, delete
SelectionDownload, duplicate, move, delete, clear
Per folderRename, move, delete

Deleting a folder takes its contents with it, and the confirmation says so — naming how many assets and subfolders are inside, rather than asking a generic question about a folder you might think is empty.

The detail drawer

Selecting an asset opens a drawer with its preview, its actions, its metadata, and editable alt text and tags.

Attaching assets to entries

A media field in the entry editor opens the same picker. What is stored on the entry is the asset id, so the same asset can be attached to any number of records without being copied.

Uploads started from inside a media field are deferred: they commit with the record’s save, so a record and its new assets are one action rather than a set of orphaned uploads if you abandon the form.

A media field can restrict what it accepts by kind or MIME type — see media fields.

Derivatives

Raster images get thumbnail and preview derivatives generated on upload, and the grid uses them — it never loads a full-size original to draw a tile.

Size limits

A single upload is capped by the plugin’s maxUploadBytes, 50 MB by default.

The upload dialog deliberately does not quote a number: no route reports the cap to the admin, and a hard-coded hint was a number nothing enforced — a file over the real cap staged happily and then failed after transferring in full. The hint says what kinds are accepted, not how big.

If you raise the cap, see media storage.

No image transformation on the way out

Derivatives are generated once, on upload, at fixed sizes. There is no on-the-fly resizing, no format negotiation, no cropping API and no focal point. If you need responsive images, generate them in your build or put an image CDN in front of the asset URLs.