Docusaurus Static Assets and Image Paths
Static assets look simple until a cover that works on localhost disappears after deploy, or an image path that includes static/ leaks into the public URL. This article explains how Docusaurus serves files from the static directory, how Markdown references them, and how a configured baseUrl changes every public path.
Where static files live
In a classic Docusaurus project the configured static directory (usually static/) is copied to the site root during build. A file at static/img/covers/example.webp is published at /img/covers/example.webp when baseUrl is /. The directory name static is a build input, not part of the public URL.
That rule is easy to forget when you copy a filesystem path into Markdown. Writing  asks the browser for a public path that includes static, which usually 404s. Prefer the public path without the directory name: .
Markdown, MDX, and imports
Markdown image syntax uses site-root public paths or absolute https:// URLs. Relative paths beside the Markdown file are resolved by the bundler when you import an asset from MDX, which is a different mechanism. Managed cover workflows that write assets.hero / assets.listing / assets.og fields expect public static paths (or confirmed remote URLs) and a theme consumer that actually renders those roles.
If your homepage cards and article heroes read assets.listing and assets.hero, registering those fields alone is not enough on an arbitrary theme. Confirm the project component that reads them—in this starter that is ArticleFrame plus the listing on the homepage.
baseUrl changes every public path
Sites hosted under a subpath set baseUrl to something like /kb/. Public image URLs must include that prefix. Docusaurus helpers such as useBaseUrl and Markdown processing account for it when you use root-relative /img/... paths in content. Hard-coding a full origin without the subpath, or prepending baseUrl twice in React, produces broken links.
When you move from a root deployment on Cloudflare Pages to a subpath (or the reverse), re-check covers, OG tags, and any hand-built src attributes in React pages. A successful local build with baseUrl: '/' does not prove the same assets resolve under /kb/.
Covers versus inline figures
Covers are page metadata: hero, listing thumbnail, and Open Graph crops. Inline figures sit in the prose where a diagram or screenshot clarifies a step. Keep their public paths stable after approval. Changing a published image in place can break caches and prior reviews; prefer a new filename or a deliberate revision workflow.
For local static hosting, keep source images under the project static tree (or the private work directory until promotion). For CDN hosting, store the versioned public URL in front matter only after upload succeeds—never invent a stand-in URL.
Practical checklist
- Put files under the configured static directory, not under a content folder that the docs plugin alone scans.
- Reference them with public paths that omit the
static/segment. - Verify
baseUrlin both development and the production build output. - Confirm the theme actually renders
assets.hero/ listing / OG roles. - Keep approved asset bytes immutable during editorial review; revise through the content workflow instead of silently overwriting.
Related reading: Choosing Local Static Images vs CDN Images and the Publishing, Revisions, and Image Management FAQ.
