Media library

Inline modes

inline ref vs inline svg — when to store the URL reference vs the actual SVG markup directly in frontmatter.

Not verified yet

A storage's inline: knob controls what shape the frontmatter value takes when an author picks or uploads a file. Two values ship:

  • inline: ref (default) — the value is the public URL or repo-rooted path, exactly as described in Frontmatter shape. Your template renders <img src={frontmatter.icon} /> (or imports the file for build-imported assets).
  • inline: svg — the value is the SVG markup string itself, dropped directly into frontmatter. Your template renders {@html frontmatter.icon} (or framework equivalent) with no import plumbing.

This page covers both — when to pick each, what the editor does, and what the trade-offs are.

inline: ref (default)

The vanilla case. The value is a URL; the consuming template renders an <img> tag (or invokes its build-time importer for no-publicUrl storages).

storages:
  uploads:
    type: repo
    path: public/uploads
    publicUrl: /uploads
    inline: ref # default; same as omitting

Picking hero.jpg writes /uploads/hero.jpg to frontmatter. Standard flow; no surprises. Use inline: ref for:

  • Photos, screenshots, hero images — anything where <img> is the right semantic.
  • File downloads (PDFs, videos, audio) — never inlinable into text.
  • Most SVGs that aren't being used as icons (illustrations, decorative graphics that don't need to be styled per-instance).

This is what every other CMS does. The inline: knob defaults here for that reason.

inline: svg

For icon libraries where you want the SVG markup live in your template, not behind an <img src=…>. The frontmatter value becomes the full SVG string:

storages:
  icons:
    type: repo
    path: src/assets/icons
    inline: svg
    mode: read-only # icons added via PR, picker is read-only

Picking check.svg writes:

icon: |
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor">
    <path d="M20 6L9 17l-5-5"/>
  </svg>

The consuming template uses raw-HTML rendering:

<!-- SvelteKit -->
{@html frontmatter.icon}
<!-- Astro -->
<Fragment set:html={frontmatter.icon} />
{
  /* React */
}
<span dangerouslySetInnerHTML={{ __html: frontmatter.icon }} />;

Why use it

The killer feature: the inline SVG inherits CSS from its parent.

<button class="text-violet-600 hover:text-violet-700">
  {@html frontmatter.icon} Save
</button>

The icon picks up text-violet-600 via fill="currentColor" / stroke="currentColor" in the SVG. With <img> you'd have to either:

  • Bake the colour into the SVG file (loses per-instance styling).
  • Use SVG sprites + <use href> (extra build step + a <svg> wrapper per icon).
  • Use an SVG-as-component build plugin (heavyweight per-framework).

inline: svg gets you native CSS styling, zero plumbing.

The other win is zero build dependencies. No SVGO loader, no Vite plugin, no Astro integration — your template just renders a string. Works the same on every framework.

Editor behaviour

When a field references an inline: svg storage:

On pick: the picker hands back the file's public URL as normal, then the editor sniffs the storage's inline: mode. For svg, it fetches the file's bytes via the signed-URL flow (POST /v1/sites/:id/media/sign + GET the signed URL) and writes the markup string to the field instead of the URL.

On drag-drop: the file gets uploaded to git as normal (so other inline-svg fields can pick the same icon later), AND the editor reads the original File client-side as text (no extra network round-trip) and writes that to the field.

On read: the editor detects inline values via value.trim(). startsWith('<svg'). When detected:

  • The display chip's URL pill flips to a violet "inline svg" badge.
  • The path display shows "… chars of SVG" instead of trying to truncate XML.
  • The preview area renders {@html displayValue} (matches what the deployed site will render).

What the bytes still live in git

inline: svg doesn't replace the upload — it augments it. When an author uploads an SVG to an inline-svg storage:

  1. The bytes get committed to git at the storage's path as usual.
  2. The bytes ALSO get inlined into the field's frontmatter as the markup string.

This means future picker selections (on other pages, other fields) can still pick the same icon from the library — the picker reads from git. Each pick that happens through an inline-svg storage inlines the bytes into its own frontmatter; the git copy is the library, the inlines are instances.

The trade-off — duplication

Every page that uses an inline icon carries its own copy of the markup in its YAML:

# pages/about.md
icon: |
  <svg viewBox="0 0 24 24"><path d="..."/></svg>

# pages/contact.md
icon: |
  <svg viewBox="0 0 24 24"><path d="..."/></svg>

# pages/team.md
icon: |
  <svg viewBox="0 0 24 24"><path d="..."/></svg>

For a 5-line SVG times 50 pages, that's 250 extra lines across your content tree. Git diffs are noisier (changing an icon means N file changes), and your build's content payload is bigger.

Compare to inline: ref:

# pages/about.md
icon: /src/assets/icons/check.svg

# pages/contact.md
icon: /src/assets/icons/check.svg

One source of truth on disk, references everywhere. The build pulls the file once (and a smart bundler de-dupes); only one place to change the icon.

When to pick which

Pick inline: svg when:

  • The icons are styled per-instance via parent CSS (text colour, size). The CSS inheritance through currentColor is the win.
  • The site is small (< 50 pages) — the duplication cost is negligible.
  • You don't want any framework-specific build plumbing for icon rendering.
  • The icon library is small and stable — changes are rare so the re-publish-N-pages cost rarely comes up.

Pick inline: ref (default) when:

  • The site is large. Every duplication costs.
  • The icons are decorative (no per-instance styling). <img> is fine; no need to inline.
  • You already have a build-time SVG pipeline (Vite plugin, Astro's Image component, etc).
  • The icon library is large or changes often — single-source-of- truth + diff hygiene beats zero-plumbing rendering.

Editor restriction: read-only storages

Inline-svg storages typically live alongside mode: read-only — icons are an asset library maintained outside the CMS (designer PRs). The picker still scopes to the storage and inlines on pick; only the upload affordance is hidden.

You CAN have a read-write inline-svg storage if you want authors to upload icons through the CMS. Less common; the inline duplication makes more sense for curated libraries.

Future inline modes

The shape of inline: is a discriminated union — ref / svg today, room for html / json / markdown later. The validator will reject unknown values until each lands, so a typo (inline: smg) fails at config-load.

If we ever ship inline: html (inline a static HTML snippet) or inline: json (inline structured data), the editor's detection heuristic generalises — sniff the value's leading characters and pick the rendering path.

On this page