Skip to Content
DocumentationBuild a websiteAssets (images & documents)

Assets (images & documents)

Images and documents live co-located in the page bundle as bare filenames — content/<slug>/<asset> (an image’s asset is hero.jpg, never a path). A site build has two jobs: turn that bare name into a URL, and get the file to where it’s served. The split that keeps this generic: the engine owns the source (assets are in content/<slug>/), the SSG owns the destination (public/, a CDN).

Resolve a URL — assetUrl

One resolver, used identically for a card thumbnail and a page-body image, so an asset resolves the same way everywhere:

import { assetUrl } from "@your-project/content-types"; assetUrl("/products/alfa-laval-sru", "image.jpg"); // → "/content/products/alfa-laval-sru/image.jpg" // a projection card thumbnail — the card already carries slug + asset: assetUrl(card.slug, card.thumbnail.asset);

It’s ${ASSET_BASE}${slug}/${asset}. ASSET_BASE comes from site.assets.base (default /content, matching a public/content/<slug>/<asset> served layout). Pass a third arg to override — e.g. an absolute CDN origin:

assetUrl(card.slug, card.thumbnail.asset, "https://cdn.example.com/content");

Everything projects the bare asset (image.jpg) — cards and bundle bodies alike — and the SSG resolves with assetUrl. Nothing pre-bakes a URL, so an asset never resolves two different ways depending on where it’s rendered.

Deliver the files — copyMeshAssets

The engine knows where every asset is; your build copies them to the served dir. copyMeshAssets mirrors the tree; you pass the destination so it stays in lockstep with ASSET_BASE:

import { copyMeshAssets, meshAssets } from "@your-project/content-types"; // in your build step — mirror content/<slug>/<asset> → public/content/<slug>/<asset>: copyMeshAssets("public/content", { status: renderableStatuses(env) });

With ASSET_BASE = /content and public/ as the served root, that lands each file exactly where assetUrl points. Prefer to run your own copy loop? Take the inventory instead:

FunctionWhat it does
assetUrl(slug, asset, base?)Resolve a bare asset → served URL (${base}${slug}/${asset}).
pageAssets(slug, opts?)One page’s co-located assets — { slug, name, path }[] (excludes index.yaml/dotfiles).
meshAssets(opts?)Every renderable page’s assets (status-filterable) — the copy-step inventory.
copyMeshAssets(dest, opts?)Mirror content/<slug>/<asset>dest/<slug>/<asset>; returns the manifest.

Point dest at the directory your ASSET_BASE maps to under the served root (ASSET_BASE /contentdest: "public/content"). The engine mirrors the <slug>/<asset> layout; keeping dest aligned with ASSET_BASE is what makes the copied file and the resolved URL agree.

Last updated on