Astro, embed an image in markdown without relative path
By Flavio Copes
Astro loads Markdown images written as file.png, with no ./ prefix, since version 4.6.4. How it works, plus the remark plugin I used on older versions.
In Markdown we can embed images like this:

or using relative paths:

Imagine you have a folder with a markdown file.md and in the same folder file.png, and you want to include that image.
This is valid Markdown, and it works in most apps and CMS:

Astro supports it too, with no extra setup. The fix landed in April 2024, during the Astro 4 cycle (PR #10801), so any Astro 5, 6 or 7 project handles it out of the box.
Astro finds file.png next to your Markdown file, optimizes it and outputs a regular <img> tag. A path into a subfolder works the same way, so  is fine too.
You can still write ./file.png if you prefer. It points to the same file.
Why I needed this
Usually it’s not a problem for me, as all images are in a separate folder under /public, served statically.
But for a project I’m working on, which has a TON of markdown files, I grew tired of using VS Code to edit markdown. I was looking for a good markdown editor that could open a folder full of markdown files, and also visually display images inside the content.
I settled on Obsidian, which I once tried for note taking but didn’t stick to it.
I found it an excellent markdown editor, with lots of options to customize it as I want it to behave.
Problem: Obsidian stores images like this in Markdown:

When I wrote this post, Astro required a ./ relative path:

There was no way to change either of them.
The fix for older Astro versions
If you’re stuck on Astro 3, or on an Astro 4 release older than 4.6.4, the images without ./ won’t load.
After some googling I found a StackOverflow answer that guided me in the right direction. I learned I could use a remark plugin to change this behavior, and add it to the Astro config in astro.config.mjs. A remark plugin works on the Markdown before Astro looks for the image files, so it can rewrite each image path.
Now the problem was finding a plugin for my needs.
I don’t know how, but I found https://github.com/Pondorasti/remark-img-links, which lets you add an absolute URL to each markdown image, to use a CDN or something. Pretty similar to my needs.
So I wrote something similar, directly in my Astro config file. It adds ./ to every image path that isn’t a URL or an absolute path:
//npm install unist-util-visit
import { visit } from 'unist-util-visit'
function fixRelativeLinksFromObsidianToAstro(options) {
function visitor(node) {
if (node.url.startsWith('http') || node.url.startsWith('/images/')) {
return
}
if (!node.url.startsWith('/')) {
node.url = './' + node.url
}
}
function transform(tree) {
visit(tree, 'image', visitor)
}
return transform
}
and I used this in my Astro config:
// https://astro.build/config
export default defineConfig({
//...
markdown: {
remarkPlugins: [[fixRelativeLinksFromObsidianToAstro, {}]],
},
})
Now even  images work in Astro.
On a current Astro version you don’t need this plugin, so if it’s still in your config after upgrading, you can remove it.
Want me to talk about your product? You can sponsor this site.
Related posts about astro: