Media library
The media library holds every image you upload to the CMS. Open Media in the sidebar.
What you see
A grid of thumbnails, paginated. Each tile shows:
- The image preview (admin-thumb variant: 240×240)
- File name
- Upload date
- Dimensions (e.g. 1920×1080)
- Type badge (image/svg/etc.)
Above the grid:
- Upload button — opens a file picker (or drag-and-drop the file onto the page)
- Search — by file name
- Type filter — All / Image / SVG
Clicking a tile opens a details panel on the right with:
- Full-size preview (admin-preview variant: 800×800)
- File name (editable)
- Alt text (used by themes for
<img alt>) - Caption (optional, used by themes that surface captions)
- File metadata (size, dimensions, content-type, upload date, uploaded by)
- Download original is NOT available — only variants are kept (see below)
- Delete button
Upload pipeline
When you upload an image, the admin runs it through a browser-side multi-variant pipeline:
- Validates — file extension matches the active theme's
inputFormats(typically.jpg .jpeg .png .webp) - Decodes the file via
createImageBitmap() - Resizes to every variant declared by the active theme plus two admin-only variants (
admin-thumb72×72,admin-preview800×800) - Re-encodes each variant to WebP (or whatever
outputFormatthe theme picked, typically WebP) - Uploads each variant under
media/<yyyy>/<mm>/<slug>-<random-hex>/<variant>.webpon Flexweg - Persists a single
media/{id}Firestore document referencing every variant by name
The original file is never stored. Only the resized variants live on Flexweg.
Why no original?
Three reasons:
- Storage cost — original photos are typically 5-50 MB. Variants are 50-500 KB each. Discarding originals saves 90%+ of the storage budget.
- Bandwidth — the public site never serves the original, only the variant the page needs. Visitors download less.
- Predictability — every image goes through the same compression settings. No mix of pristine originals and lossy variants.
The trade-off: switching to a theme that asks for a larger variant doesn't regenerate from the original (it's gone). The pickFormat(view, "huge") helper falls back: requested → defaultFormat → largest available → empty string. So existing images don't render broken — they just appear at the next-best variant.
If you need maximum quality for an image, keep your high-res source files outside the CMS (e.g. in cloud storage / Lightroom catalog) and re-upload when needed.
Variants per active theme
Each theme declares its image format catalog in its manifest:
// Default theme example
imageFormats: {
inputFormats: [".jpg", ".jpeg", ".png", ".webp"],
outputFormat: "webp",
quality: 80,
formats: {
small: { width: 480, height: 480, fit: "cover" },
medium: { width: 800, height: 800, fit: "cover" },
large: { width: 1600, height: 900, fit: "cover" },
},
defaultFormat: "medium",
}
When you upload, the admin generates small.webp, medium.webp, large.webp, plus admin-thumb.webp and admin-preview.webp (always present regardless of theme).
Different themes ship with different formats. Magazine uses larger heroes; corporate uses square service images. Switching themes doesn't regenerate existing media — old uploads keep their original variant set, and pickFormat() chooses the best available.
File organisation on Flexweg
media/
├── 2026/
│ ├── 05/
│ │ ├── photo-vacation-a3f7b2/
│ │ │ ├── admin-thumb.webp
│ │ │ ├── admin-preview.webp
│ │ │ ├── small.webp
│ │ │ ├── medium.webp
│ │ │ └── large.webp
│ │ └── another-photo-b8e9c1/
│ │ └── …
│ └── 04/
│ └── …
└── 2025/
└── …
Each upload gets a folder named <slugified-filename>-<6-char-hex>. The hex suffix guarantees uniqueness — re-uploading a file with the same name doesn't overwrite an existing folder.
Inserting media in a post
The media picker is reusable across the admin:
- In the editor — use the Image block (
/imagein the inserter). The picker opens with the library + an upload tab. - As a hero on a post — Document sidebar → Hero image field → opens the picker
- As an avatar — Profile → Avatar field → opens the picker
- In theme settings — themes that have logo / banner fields use the same picker
- In plugin settings — same
Picking an image inserts a MediaView reference (the Firestore id + resolved view), not a hardcoded URL. So if you later replace the image (delete + re-upload with the same id — not currently supported), every reference would update. In practice, you delete + re-upload as a new image and update the references manually.
Inserting media via URL
The Image block's inspector has a "From URL" input. Pasting an external URL embeds the image without uploading. Useful for stock-photo CDNs or content already hosted elsewhere.
⚠️ Note: external URLs aren't variant-resized by the CMS. The browser loads them directly. They could break if the external host moves the file.
Deleting media
Click a tile → details panel → Delete. Confirms, then:
- Calls
flexwegApi.deleteFolder("media/yyyy/mm/<slug>-<hex>/")— wipes the entire variant folder atomically - Removes the
media/{id}Firestore document
⚠️ Posts that reference the deleted media still link to it. Themes' pickFormat() returns an empty string for missing media, so the rendered HTML has empty <img src=""> (typically rendered as a broken-image icon). The admin doesn't currently scan for orphan references.
To find orphan references before deleting: search your posts for the image's filename or id (the search bar in Posts doesn't search bodies, but Firestore queries via the Console can).
Bulk operations
Select one or more rows via checkboxes → bulk delete is the only currently-available bulk action.
(No bulk reassignment of alt text, no bulk re-encode. These would be useful additions for a future version.)
Maximum file size
Limited by Flexweg's plan's /files/upload size limit (typically 10 MB per file on the standard tier). The admin doesn't enforce a client-side limit; you'll get a 413 from Flexweg if you go over.
For images larger than the limit:
- Resize them locally before upload (modern phone cameras produce 8-15 MB — typical 1080p compressed to ~500 KB still looks great)
- Use Flexweg's CDN-friendly serving to handle delivery efficiency, not storage size
Continue
- Posts → Hero image — assigning a hero
- Theme image formats — for theme authors who want to declare custom variant catalogs