In the previous article, we added support for parsing Markdown Frontmatter. This allows our document metadata (like the title) to be defined within the Markdown file along with the content, avoiding hard-coding.
Besides text and code, a document usually includes static resources like images.
Currently, if you reference an image in hello.md, it won't display. In this article, we will solve this problem by enabling FastAPI to correctly handle and serve static resources, like images, referenced in our Markdown files.
Why Won't the Image Display?
Here is a Markdown document that includes an image leapcell-logo.png:
# Hello, Markdown!
Here is a Logo:

If you run the server and visit this document, the image will fail to load.
This is because the image path is ./leapcell-logo.png. When the browser requests this path from the /docs/hello page, the actual URL it requests is http://127.0.0.1:8000/docs/leapcell-logo.png.
However, in our FastAPI application, there are no routes or mounted directories configured to handle the /docs/leapcell-logo.png request, so the image fails to load.
Step 2: Create a Convention for Document Resources
We need a way to serve these images. The lazy approach would be to put all images in the static folder, but a better practice is to separate content resources (like leapcell-logo.png) from the main static directory and place them in a dedicated folder, for example, docs/assets.
Update the directory structure as follows:
fastapi-docs-site/
├── docs/
│ ├── assets/ <-- New
│ │ └── leapcell-logo.png <-- Resource file
│ └── hello.md
├── main.py
├── static/
│ └── css/
│ └── highlight.css
└── templates/
Step 3: Mount the Document Resource Directory in FastAPI
Now, we need to tell FastAPI: "Any request beginning with /docs/assets/ should look for files in the docs/assets/ folder."
Open main.py and modify it as follows:
# main.py
from fastapi import FastAPI, Request
from fastapi.templating import Jinja2Templates
from fastapi.responses import HTMLResponse
import markdown
from fastapi.staticfiles import StaticFiles
import frontmatter
app = FastAPI()
# This is our newly added "assets" directory for document content
# Note: The mount path is "/docs/assets", the physical directory is "docs/assets"
app.mount("/docs/assets", StaticFiles(directory="docs/assets"), name="doc_assets")
# Other code remains unchanged
Note that we are mounting /docs/assets and not /docs. This is for security: we only want to expose resources like images in the assets folder, and avoid exposing the .md source files from the docs/ directory.
Step 4: Update the Image Link in Markdown
Now we can reference the image in Markdown according to our configured static path.
Edit docs/hello.md:
---
title: "Hello, Frontmatter!"
author: FastAPI Developer
date: 2025-11-09
---
# Hello, Markdown!
This is the first Markdown document we've rendered with FastAPI.
Here is a Logo:

Step 5: Run and Test
Run uvicorn main:app --reload to start the server.
Visit http://127.0.0.1:8000/docs/hello in your browser.
You will see that the leapcell-logo.png image you added is now correctly rendered on the page.
Summary
With some simple configuration and conventions, we've enabled our Markdown documents to include images and render them correctly.
As we add more documents, our site should have a side navigation bar to list all available documents. Of course, this should also be generated automatically.
In the next article, we will dynamically generate this sidebar by automatically scanning the docs/ directory and change the site to a "left-sidebar, right-content" layout.
Other
After building your site, you might want to deploy it online for others to see. But most cloud platforms are expensive, and it's not worth paying a high price for a practice project like this.
Is there a more economical way to deploy? You can try Leapcell. It supports deploying multiple languages like Python, Node.js, Go, and Rust, and offers a generous free tier every month, allowing you to deploy up to 20 projects without spending a dime.
Follow us on X: @LeapcellHQ
Read other articles in this series
Related Posts:



Top comments (0)