Hugo Image Storage Showdown: Local, Cloudinary, and Cloudflare R2
A comprehensive guide to image storage in Hugo! This article explores three common image storage solutions: local storage in Hugo projects, Cloudinary hosting, and Cloudflare R2 storage, analyzing their implementation, pros and cons.

- Carrie
- 6 min read

When building a static website, images are essential for enhancing visual appeal, improving user experience, and boosting search engine optimization (SEO). This article dives into three popular image storage solutions for Hugo websites, analyzing their implementation methods, advantages, and drawbacks to help developers choose the best approach for their projects.
- Local storage in Hugo projects
- Cloudinary image hosting
- Cloudflare R2 storage
Introduction
As a new Hugo blogger, I love adding images to my posts to make them more engaging. Images not only bring my content to life but also attract readers and improve SEO. However, managing images efficiently in a Hugo project can be a challenge. The storage method you choose impacts your site’s performance, maintenance costs, and development experience.
In this post, I’ll share my experience with three image storage solutions, detailing how they work, their pros and cons, and my personal thoughts, hoping to inspire fellow Hugo bloggers!
Local Storage in Hugo Projects
Solution Overview
Local storage involves saving images directly in the Hugo project’s file system, typically in the static/
directory or alongside content files. This is Hugo’s default image management approach, ideal for quick development and small projects. Images are treated as static assets, bundled with the project during the build and deployed to the server.
Storage Methods
In my Hugo projects, I store images in these locations:
- Static Directory (
static/
): Hugo’s default folder for static assets, perfect for global images like logos or backgrounds. For example,static/images/logo.png
is accessible via/images/logo.png
. - Content Directory: Images can be stored alongside Markdown files (e.g.,
content/posts/my-post/
), ideal for post-specific images. - Theme Directory: For custom themes, images can go in
themes/<theme-name>/static/
.
In Markdown files, I reference images using relative or absolute paths:

Hugo’s resources
pipeline also allows image processing. For instance, I use a shortcode to resize images dynamically:
{{ $image := resources.Get "images/example.jpg" }}
<img src="{{ ($image.Resize "800x600").RelPermalink }}" alt="Example">
✅ Advantages
- Simplicity: No third-party services needed—just drop images into the project folder.
- Version Control Friendly: Images can be managed with Git alongside code, making collaboration easy.
- Convenient for Local Development: No internet required; images display perfectly in local previews.
- No Extra Costs: Free except for server storage, ideal for budget-conscious projects.
❌ Disadvantages
- Repository Bloat: Large or high-resolution images inflate the Git repository, slowing down cloning and pushing.
- Performance Limitations: Image loading depends on server performance; without a CDN, it can be slow.
- Optimization Challenges: Manual compression or external tools (like TinyPNG) are needed, and Hugo’s built-in processing is limited.
- Not Scalable: Managing and distributing many images becomes complex for larger projects.
Cloudinary Hosting
Solution Overview
Cloudinary is a powerful cloud-based image management platform offering storage, optimization, dynamic processing, and CDN delivery. With API and URL-based controls, it’s perfect for Hugo projects needing high-performance image handling.
Storage Methods
Here’s how I use Cloudinary for image hosting:
Sign Up and Upload: Register on Cloudinary’s website, upload images, and get a public URL.
Reference in Hugo: Use the Cloudinary URL in Markdown or templates:

Dynamic Optimization: Adjust images via URL parameters, like resizing or converting to WebP:

Automation: Use Cloudinary’s SDK or API to script batch uploads or sync images from my Hugo project.
✅ Advantages
- Automatic Optimization: Cloudinary compresses images and supports formats like WebP, reducing load times.
- CDN Acceleration: Global CDN ensures fast image delivery, especially for international audiences.
- Dynamic Processing: Real-time resizing, cropping, and effects make it great for responsive designs.
- Reduced Local Storage: No need to store images locally, keeping the Git repository lean.
❌ Disadvantages
- Cost: Free tier is limited; high usage requires paid plans.
- Third-Party Dependency: Relies on Cloudinary’s uptime; network issues could affect images.
- Learning Curve: URL parameters and APIs require some learning, though documentation helps.
- Privacy Concerns: Storing images on a third-party platform may raise data privacy issues.
Cloudflare R2 Storage
Solution Overview
Cloudflare R2 is a cost-effective object storage service, similar to AWS S3, designed for static assets. Integrated with Cloudflare’s CDN, it’s ideal for Hugo projects needing scalable, high-performance storage on a budget.
Storage Methods
Here’s my process for using Cloudflare R2 in Hugo:
Create a Bucket: Set up an R2 bucket in the Cloudflare dashboard and upload images.
Configure Access: Make the bucket public or use Cloudflare’s CDN for delivery.
Get URLs: Use the R2 URL in Hugo:

CDN Integration: Use Cloudflare’s custom domains and caching to optimize delivery.
Automation: Use R2’s API or tools like
wrangler
for batch uploads.
✅ Advantages
- Low Cost: R2’s storage and bandwidth fees are significantly lower than traditional cloud storage.
- High Performance: Cloudflare’s CDN ensures fast global delivery.
- Scalability: Handles large volumes of images, perfect for high-traffic sites.
- Flexibility: Cloudflare Workers allow custom optimizations.
❌ Disadvantages
- No Built-In Optimization: Unlike Cloudinary, R2 lacks dynamic image processing; manual optimization is needed.
- Complex Setup: Configuring buckets, CDN, and permissions can be daunting for beginners.
- Cloudflare Dependency: Requires familiarity with Cloudflare’s ecosystem.
- Manual Optimization: Compression or format conversion requires external tools or Workers.
Comparison of the Three Solutions
Performance
- Local Storage: Loading speed depends on server performance; without a CDN, it’s slower for global users.
- Cloudinary: CDN and automatic optimization deliver lightning-fast loading, ideal for high-traffic sites.
- Cloudflare R2: Fast with CDN, but manual optimization is needed for best results.
Cost
- Local Storage: Free, but server storage and bandwidth costs grow with traffic.
- Cloudinary: Free tier suits small projects; larger sites incur usage-based fees.
- Cloudflare R2: Low-cost storage and bandwidth, great for budget-conscious projects.
Ease of Use
- Local Storage: Easiest—just add images to the project folder, no extra setup.
- Cloudinary: Requires learning URL parameters or APIs, but documentation is beginner-friendly.
- Cloudflare R2: Involves setting up buckets and CDN, better for those familiar with Cloudflare.
Use Cases
- Local Storage: Best for personal blogs, small projects, or rapid prototyping.
- Cloudinary: Ideal for sites needing dynamic image processing and responsive designs.
- Cloudflare R2: Suits budget-limited projects with large image libraries or high traffic.
Conclusion
Choosing the right image storage solution for your Hugo project involves balancing performance, cost, and ease of use.
After experimenting, I started with local storage for its simplicity and zero cost, perfect for my early blogging days. However, as my blog grew, I considered scalability.
After researching via AI tools and comparing Cloudinary and Cloudflare R2, I settled on R2. Since I was already using Cloudflare’s CDN, integrating R2 was seamless, and it’s been smooth sailing so far. These insights are my take as a beginner blogger—hope they help you find the right fit for your Hugo site!