One issue I ran into pretty quickly in Zola was: how do you reference images in the markdown of a post?

Sure, you can place your images in the static/ directory - but that disconnects them from your post content.

content/
  2025/
    05/
      my-first-post.md
static/
  images/
    example.jpg
![My Image](/images/example.jpg)

Ideally, I'd like to store images alongside my posts. This helps keep static assets organized long-term and makes it easier to see which images belong to which post.

content/
  2025/
    05/
      images/
        example.jpg
      my-first-post.md

At first glance, Zola can't locate the image in this structure. No matter what path you try, example.jpg is never deployed to the public/ directory. So, this approach doesn't work.

![My Image](example.jpg)                  # Doesn’t work
![My Image](images/example.jpg)           # Doesn’t work
![My Image](/2025/05/images/example.jpg)  # Doesn’t work

So what can we do? Turns out the Zola docs do contain the answer - but it's a little hard to find.

Looking up the documentation on asset co-location reveals that Zola does support co-locating static assets alongside posts.

The trick is to switch from a flat structure of posts like this:

content/
  2025/
    05/
      my-first-post.md
      my-second-post.md

To Page Bundles. Let's give it a try:

content/
  2025/
    05/
      my-first-post/    # The post slug is now the directory name
        images/         # Images or other static assets are stored inside
          example.jpg
        index.md        # The post content is moved into an `index.md` file

Zola's markdown processor can now correctly find co-located assets using a relative path:

![My Image](images/example.jpg)

This structure has several benefits:

  • Static assets are co-located with the post, keeping everything logically grouped.
  • Paths to assets are simpler and less error-prone.
  • You avoid filename conflicts (two different posts can use images with the same name).