Static image URLs for RSS in Astro

Published on: 24/06/2026

Last edited on: 24/06/2026

Motivation

I have talked about image handling problems in Astro before. My main gripe was the usecase of RSS, while it is an excellent integration in Astro, there are some interesting corner cases when it comes to images and MDX. MDX is hard to handle in general, combination of JSX and MD? Recipe for confusion. So it is understandable that Astro is still figuring out ropes on it. But image handling? That’s a different case. Astro does helpfully provides ways to optimize images used in your blog, but its integration with its own RSS plugin has a gotcha. Image URLs generated by astro on each build are not the same. A typical astro generated image URL is of the form:

https://basedomain.com/_astro/image_name.hash.webp

image_name is the file name of the image in your project, but the hash, that can change! That means an image can have one URL in todays build, but a completely different URL in tomorrows build. This is not a problem if everyone visits your website for reading your blogs, but when sending content over RSS to readers, they may decide to cache it, which would mean those URLs would stop loading! I do not want that to happen. That means I need a saner way to get static URLs for an image.

Second problem, is more about the structure of the project. Currently, I have blogs as a submodule in website repo, this allows me to keep everything in blogs repo as markdown files and deal with just code in the main website. This also allows me to add a private submodule, which I have recently done it the form of weeknotes. I want my weeknotes to have a static link, but not listed anywhere and only show the latest one in RSS feed. I dont want to lay out my full life for someone to see on a github public repo, but also keep sharing latest tid-bits about myself to my friends. My current structure had all images in the website repo, which would have broken this private arrangement of weeknotes. So I wanted to move all the images just next to the blog post, in the same dir. My current structure for blogs is:

  blogs git:(main)  tree
.
├── non-tech
│   ├── 2024
│   │   └── writing-more
│   │       └── BLOG.md
....
├── README.md
└── tech
    ├── 2021
    │   └── ieee-ctf
    │       └── BLOG.md
...
34 directories, 23 files

i.e. main segregation of tech/non-tech as categories, year wise segregation, slug as the dir name under year and finally, a file named BLOG.md containing the actual blog, and now, all the images alongside it. This is a really good structure! It makes logical sense to keep images just next to the associated blog entries. Theres another reason I mentioned this structure here, which will come to help later, so keep it in mind.

Thridly, I was also using MDX in my blogs/weeknotes, this was done initially to just get the website with blog integration out. One battle at a time. JSX allowed me to import images using import, which was handy and it also allowed me to resize images with ease. I couldnt use img tag cause that needed static URLs and couldnt use markdowns img syntax cause that did not allow resizing of images. The problem with having JSX in your blog content is it gets bundled in my RSS content, that was super annoying to see! I could have written a custom extension to remove the imports from markdown to HTML converter, but that does not seem like a clean solution to me. Any tags I add in future, would mean me remembering to remove them from the RSS HTML generator.

So in summary, main motivations were:

Solution

Lets tackle one thing at a time, but you would see how all of this comes together at the end. Also why I am writing about these things together.

First thing, lets talk about improving structure. I moved images from website repo to individual blogs/weeknotes repos and did not remove import JSX statements. This was easy to do, I just added:

"@blogs/*": ["./blogs/*"]
"@weeknotes/*": ["./weeknotes/*"]

to my tsconfig.json and that allowed me to write import statements without worrying about relocating submodules in the future! But I still had to write down full paths from base of the submodule project to the blog post.

Next let’s talk about static URLs. I was talking about this problem with Harsh in last IndieWebClubBlr meetup and he mentioned I should dump all images in public/ folder and that would give me static URLs for all of them. I decided to do just that, but at build time! So I wrote a bash script which:

What do I mean by same dir structure? For example, if an image is at ./blogs/non-tech/2026/chinaga-betta-hike/amongst-the-clouds.jpeg, it goes into public/ as public/rss-images/blogs/non-tech/2026/chinaga-betta-hike/amongst-the-clouds.jpeg. Now this was easier to do because I fixed the dir structure above to move images right next to the blog! That means I get structured image URLs without much effort!

Next step was converting all the MDX files to MD by replacing image imports with img tags and href as public/rss-images/... URLs. I could do this now because I had static image URLs, I get resizing benefits and simple markdown supported HTML without much hassle.

Three birds with one stone!! 🐦🪨

Gripe

What I dont like about this solution is:

I am more worried about second, cause image loading can be an important metric in website load times, but I will think about optimizing this in future.

Conclusion

For now, enough building, I am going to focus on writing more! Part of it was writing this blogpost, and hopefully many more to come!