media

File uploads for the CMS (this example has it enabled — the Articles form has a cover field). Bytes live on disk in the site’s media/ folder (fixed location, created on start), metadata in a built-in media table; SQLite never stores blobs, so the database stays small and backup = database + the media folder.

keydefaultdescription
url_prefix/mediapublic URL prefix; must not overlap static, /cms, /soe or routes
max_file_size5mper-file limit, a number or "5m" / "500k"; hard ceiling 100m
typespng, jpg, gif, webp, pdfallowed types — a subset of that list

A stricter variant of this site's block, three types instead of five:

"media": {
  "url_prefix": "/media",
  "max_file_size": "5m",
  "types": ["png", "jpg", "webp"]
}

The file type is detected from content, not from the name. The server reads the magic bytes, assigns the canonical extension (a JPEG is always .jpg) and rejects anything it cannot recognize — an .exe renamed to .jpg does not pass. Nothing client-supplied is stored: the file name is the record id, so /media/0/12.jpg. svg is not supported deliberately — it is XML that can carry scripts.

How it works day to day: add { "name": "cover", "widget": "file" } to a form's fields (the column is plain text — it stores the url). Picking a file uploads it immediately and puts the url into the field. The Media section in the admin lists everything uploaded, with an upload button of its own: add a picture there, copy its link and paste it wherever it is needed (deleting is admin-only). Files are served with a long-lived immutable cache header — content under an id never changes — plus X-Content-Type-Options: nosniff.

Uploads require sign-in (any role); files are sharded on disk 1000 per folder — the /media/0/ part of the url is that shard. Remove the block to disable the feature entirely: no table, no routes, no folder.

A site template can ship pictures pre-loaded: see "Pre-loaded uploads" in the seed article.

← All articles in this group