Skip to content

Astro, embed an image in markdown without relative path

I hit this problem today: you know, you markdown we can embed images like this:

![](/path/to/file.png)

or using relative paths:

![](../file.png)

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:

![](file.png)

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

![](./file.png)

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

![](file.png)

Astro requires you to use a ./ relative path

![](./file.png)

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 ![](file.png) images work in Astro.


→ Here's my latest YouTube video

→ I wrote 17 books to help you become a better developer, download them all at $0 cost by joining my newsletter

JOIN MY CODING BOOTCAMP, an amazing cohort course that will be a huge step up in your coding career - covering React, Next.js - next edition February 2025

Bootcamp 2025

Join the waiting list