Blog
Tags
Agentic AIVibe CodingsubagentsMCPCDNClaude Sonnet 4Claude Codeslash commandsmeta
Posts
It's Enough Slices!! (er, files)
Using a CDN to host my blog images.
Tags: CDN, meta
In the process of writing my blog series on agentic AI, I quickly realized I would be storing far too many screenshots for my own sanity—and for your bundle size. We need a CDN.
I maintain this site and blog manually. Not because I think I can do it better than Wordpress, but because giving myself full control and forcing myself to make all features and improvements as the blog grows keeps me writing code. I certainly know that writing code may not be the most desired skill in July 2025, but I think the fundamental knowledge and ablity to solve a problem will always be valuable.
I looked at Cloudflare, which is arguably the most popular image hosting service, but I was unhappy with the interface...
...and the immediate loss of quality in uploaded images.
Cloud...something?
After a bit more searching, I landed on Cloudinary (whose name I am constantly having the hardest time recalling, for some reason). Cloudinary has a great user interface, folders, an asset collection option, and tagging—including alt text tags. Not to mention the transformations and effects available.
It's just a filter! Give me a filter
There is a React SDK available, which allows you to easily access your "cloud" and grab images using their public ID to integrate them into your site. But I was quickly curious about whether I could request a group of images, such as all the images for a single blog post. That would make it possible for me to programmatically make them available to my blog post component, rather than having to specify each image to retrieve and keep in mind how many there are per post.
My initial research was disappointing, as it seems most of the robust API access is only available through the Admin API (and for good reason). But while this site should have a backend, I wasn't ready to dedicate time to that with the other projects I'm prioritizing at the moment. I only want to access a filtered list of assets, not perform updates at this time. Was there any way to do this?
Luckily, yes. I chanced upon this post, which describes a method of accessing tagged assets in your cloud with a simple GET request. This should allow me to organize my images and retrieve only the group I need.
I was storing all my images in the project filestructure until now. I'll keep some here, such as the site logo. But images for blog content are moving to the cloud.
I used the Cloudinary folders feature to create the structure in which I would store my blog posts. Then I just selected all the images in each folder and tagged them with a blog post identifier: blogPost0001, etc.
When I tested to make sure the GET request properly retrieved my images, I was met with an "access denied" error response. Why?
Stay for the whole lesson
As it turns out, there is a default protection in the Cloudinary settings that keeps your list of Resources private. You can turn this off to allow unauthenticated access to things like lists of items with a particular tag. This was mentioned in the post I referenced, but I missed it.
Under "Restricted image types," uncheck "Resource list".
Click the image to visit a page where you can copy the code.
Now we're receiving a list of images for a particular tag. We're already blogging the hard way, by writing our own page structure in JSX. How can we use this list of images to keep the process of creating and editing blog posts relatively simple?
Look it up
My blog page uses React Router and its Outlet component to create a page framework around the blog content. Because the nested BlogContent component renders only the post we've selected along with its metadata, we can retrieve the images for that post there.
Once we get the list, we want to map the array into a dictionary that we can use to easily access our images by the sequence number. I have a standardized way of naming these files (e.g., blog-post0002-image001, which gets translated into something like blog-post0002-image001_kj4us, so the original filename is preserved), so it's possible to just parse their public_id value for now to get a good object key.
Click the image to visit a page where you can copy the code.
Which gives us this. Of course, if there is a banner, it will be titled blog-post0001-banner-[etc], so banner will be its key.
Click the image to visit a page where you can copy the code.
Now that we can do that, we can just use the AdvancedImage component from the React SDK to render the images, right? Not quite.
Let the component handle its own concerns
We need to provide ourselves a way to easily transform each unique image before we render it, and we don't want to do all that for each image in the body of each blog post component. We can create a wrapper component that gives us an API to perform the transformations we want via props.
Click the image to visit a page where you can copy the code.
This way, we are retrieving each image from the Cloudinary url-gen SDK automatically, performing our transformations, and rendering it.
A single source
Each CloudinaryImage wrapper component needs access to the Cloudinary instance, but we don't have to get a new instance each time. We can just do it once and keep it in React Context.
So we set up our Context.
Click the image to visit a page where you can copy the code.
And then wrap our Provider around the app and pass in the Cloudinary instance. In React v19, you can just call the Context as a component (you don't need the .Provider). But I'm working in v18 for time being.
Click the image to visit a page where you can copy the code.
Now we can remove the Cloudinary instance call from our code in the wrapper component.
Click the image to visit a page where you can copy the code.
Once that's done, we can just access the single Cloudinary instance within each CloudinaryImage component.
An improvement with promise
So now we can just call our CloudinaryImage component in a simple manner and access the images in our CDN.
Click the image to visit a page where you can copy the code.
And with that, all the blog content images are being served through Cloudinary, the app bundle size will stay reasonable, and I can easily implement any transformations I want to apply to the images in the future.