Sources, best first:
filePath— local stdio server only (the hosted server rejects it). Best for files on disk at any size: bytes go straight to the CDN, EXIF rotation applied, AVIF/HEIC become JPEG, wider than 2680px is downscaled. Pass an array to upload many.imageUrl/fileUrl— a public URL. Pass the ORIGINAL full-resolution URL, never one with?w=/h=/q=resize params (that stores a permanently downscaled copy).dataBase64— last resort. The serverless request cap is 4.5MB, so ~3MB decoded, and it costs ~1.4 tokens per byte. PassmimeTypefor non-images so they route to R2.
Using the result:
- Images:
{{ '<mediaId>' | image_url: width: 800 }}is the CDN URL (<img src="…">, a backgroundstyle).image_tagturns a URL into an<img>, so it always comes afterimage_url:{{ '<mediaId>' | image_url: width: 800 | image_tag: alt: '…', class: '…' }}(it takesalt,class,width,height,loading,sizes,fetchpriority). A bare{{ '<mediaId>' | image_tag }}writes the id as the src: a broken image. Use the mediaId, never the raw url. - Video/audio/pdf/zip (R2):
{{ '<mediaId>' | file_url }}works in an<a>,<video src>,<audio src>or a collection url/media field.
Favicon (set_favicon): exactly one of filePath (stdio), mediaId, imageUrl, dataBase64, svgContent (only SVG markup the user supplied — never invent it), or clear: true. Best input: a 512px square PNG or an SVG; .ico can't be stored. Written to site.json favicon, staged like any edit (publish to see it live); browsers cache favicons hard.