media
File uploads for the CMS (this example has it enabled — the Articles form has a cover field). Bytes live on disk, metadata in a built-in media table; SQLite never stores blobs, so the database stays small and backup = database + the media folder.
| key | default | description |
|---|---|---|
| path | — | required: folder for uploaded files, created on start |
| url_prefix | /media | public URL prefix; must not overlap static, /cms, /soe or routes |
| max_file_size | 5m | per-file limit, a number or "5m" / "500k"; hard ceiling 100m |
| types | png, jpg, gif, webp, pdf | allowed types — a subset of that list |
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 table's form_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 (deleting is admin-only). Files are served with a forever-cache header (immutable) — 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.