Astro, embed an image in markdown without relative path
I hit this problem today: you know, you 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.
Apparently Astro can’t work with this syntax to include a file in the same folder as the markdown file, which is valid markdown and works in most apps and CMS:

Instead, it requires you to use a ./ relative path

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, and 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

Astro requires you to use a ./ relative path

No way to change either of them.
After some googling I found a StackOverflow answer that guided me in the right direction, because I learned I could use a remark plugin to change its behavior, and I could add that to the Astro config in astro.config.mjs like this:
import { defineConfig } from "astro/config"
import SOMEPLUGIN from "SOMEPLUGIN"
export default defineConfig({
markdown: {
remarkPlugins: [
[SOMEPLUGIN, {
SOMEOPTIONS
}]
]
}
})
Now the problem was finding a plugin for my needs.
I don’t know how but found this: 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:
//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.
download all my books for free
- javascript handbook
- typescript handbook
- css handbook
- node.js handbook
- astro handbook
- html handbook
- next.js pages router handbook
- alpine.js handbook
- htmx handbook
- react handbook
- sql handbook
- git cheat sheet
- laravel handbook
- express handbook
- swift handbook
- go handbook
- php handbook
- python handbook
- cli handbook
- c handbook
subscribe to my newsletter to get them
Terms: by subscribing to the newsletter you agree the following terms and conditions and privacy policy. The aim of the newsletter is to keep you up to date about new tutorials, new book releases or courses organized by Flavio. If you wish to unsubscribe from the newsletter, you can click the unsubscribe link that's present at the bottom of each email, anytime. I will not communicate/spread/publish or otherwise give away your address. Your email address is the only personal information collected, and it's only collected for the primary purpose of keeping you informed through the newsletter. It's stored in a secure server based in the EU. You can contact Flavio by emailing [email protected]. These terms and conditions are governed by the laws in force in Italy and you unconditionally submit to the jurisdiction of the courts of Italy.