Issue: Handling External (Cloudflare) Images with Unknown Count in Hugo Context

In single.html, car images are loaded from Cloudflare URLs, not from Hugo assets.

Because Cloudflare images are external and not part of the Hugo project, Hugo cannot determine at build time:

  • How many images exist for a car
  • Whether a specific image URL exists or not

This means Hugo cannot use .Resources or any asset-based logic to detect image count or validity.


Current Implementation

To render images, we use a fixed loop:

{{ range seq 1 10 }}

This assumes that each car has exactly 10 images.


Problems With This Approach

1. Broken image URLs (HTML Proofer errors)

If a car has fewer than 10 images, Hugo still generates URLs for images that do not exist on Cloudflare.

  • These URLs return 404s
  • HTML Proofer reports them as broken links

2. Missing images

If a car has more than 10 images, only the first 10 are rendered.

  • Any images beyond 10 are never shown

Why This Happens

Hugo cannot query or validate external Cloudflare images at build time.

Specifically, Hugo cannot:

  • Check how many images exist on Cloudflare
  • Verify which image URLs are valid

Because of this limitation, the template must rely on a guessed fixed range, which is unreliable.


Summary

  • Hugo does not know the real image count from Cloudflare
  • Fixed loops generate invalid image URLs
  • HTML Proofer fails on non-existent images
  • Images beyond the fixed limit are not displayed

Question

What is the recommended or best-practice way in Hugo to handle external images (like Cloudflare) when the image count is unknown at build time?

Specifically:

  • How can we avoid generating broken image URLs?
  • Is there a better pattern than using a fixed seq loop?
  • Should this be handled via front matter, data files, JavaScript, or another approach?

Your description is a bit vague, but if your images have meaningful file names that somehow relate to the current context (presumably a page param), you can use the resources.GetRemote function with the Cloudflare API to list all the images, then filter that list with the collections.Where function (e.g., look for file names starting with prius_ or rav4_).

We cache the API response, so subsequent requests (e.g., one on each page) will be fast. Or you can download the list before the build and stuff it in the assets directory.

Thanks, that’s helpful. I understand the resources.GetRemote approach and how its caching works in Hugo.

However, in our case the images are stored in Cloudflare R2, not Cloudflare Images. Cloudflare R2 does not provide a public API to list objects from the bucket at build time. Because of this, Hugo cannot fetch or infer the list of images stored in R2.

As a result, there is no reliable way for Hugo to know how many images exist or whether a specific image exists during the build process.

In Cloudflare R2, we use the following folder structure and naming convention for car images:

cars/
  exterior/
    main.jpg        (default image shown when the car details page loads)
    exterior-1.jpg
    exterior-2.jpg
    exterior-3.jpg

  interior/
    interior-1.jpg
    interior-2.jpg
    interior-3.jpg
  • This folder structure exists inside the Cloudflare R2 bucket.
  • cars/exterior/main.jpg is always used as the default image on the car details page.
  • Exterior and interior images use a consistent numbered naming convention.

The main image path is stored in the Markdown (MD) file, for example:

cars/car-1/exterior/main.jpg

Using this main image path, we generate the URLs for the other images by changing the file name (for example, exterior-1.jpg, exterior-2.jpg) while keeping the same base path.

Because Hugo cannot determine how many exterior or interior images exist in Cloudflare R2 at build time, we currently use a fixed loop such as:

{{ range seq 1 10 }}

This approach has clear limitations:

  • If a car has fewer than 10 images, Hugo still generates URLs for images that do not exist.
  • If a car has more than 10 images, images beyond 10 are not displayed.
  • This can result in unnecessary image requests and missing images.

These limitations exist because Cloudflare R2 does not allow Hugo to dynamically list or count images during the build process.

Are you sure about that?
https://developers.cloudflare.com/r2/api/s3/api/

I’ve checked the Cloudflare R2 S3-compatible API documentation:
S3 API compatibility · Cloudflare R2 docs

To use the R2 API, Cloudflare requires Access Key ID and Secret Access Key. While this is secure, it also means:

  • credentials must be generated and managed,
  • secrets must not be exposed in client-side code,
  • additional setup is required just to list or fetch objects.

Because of this, using the R2 API directly (especially during build or for simple listing use cases) feels more complex than expected compared to public object access.

That’s why I’m trying to understand whether there’s a simpler or recommended approach for this use case, or if API access with tokens is the only supported option.

Appreciate any clarification—thanks.