Using Hugo Pipes to Generate Responsive Images Without External Tools
Learn how Hugo’s built‑in image processing (Hugo Pipes) can resize, fingerprint, and create responsive srcset attributes without external tools, plus the trade‑offs to watch for.
17 Jul 2025, 07:08 UTC

Problem: Manual image optimization slows down development
When building a Hugo site, you often need to serve images that are both fast‑loading and look good on any screen. Doing this manually—resizing, converting to WebP, and writing srcset markup—creates extra steps, introduces inconsistencies, and forces you to keep processed files in version control.
Thesis: Hugo’s built‑in image processing (Hugo Pipes) can automate resizing, fingerprinting, and responsive srcset generation directly in templates, keeping original assets untouched and leveraging caching for fast rebuilds.
1. Install the extended Hugo binary and verify
Image processing requires the extended version of Hugo, which bundles libvips or the Go image library. Install it via your package manager or download from the official releases.
# Example for macOS with Homebrew
brew install hugo-extended
# Verify the build includes the 'extended' tag
hugo version
# Expected output contains "extended"
# hugo v0.140.0 extended ...
Run the command in your project’s root directory. No special permissions are needed; the binary only reads files you own.
2. Basic pipe: resize and fingerprint a single image
Place a source image in assets/images/photo.jpg. In any template (e.g., a partial or a page template) you can chain Hugo Pipes:
{{/* Get the original resource */}}
{{ $img := resources.Get "images/photo.jpg" }}
{{/* Resize to 300px width, keep aspect ratio, then add a content‑based fingerprint */}}
{{ $processed := $img | resize "300x" | fingerprint }}
{{/* Output an tag using the permalink of the processed file */}}
When you run hugo server (or hugo for a full build) from the project root, Hugo creates a cached version under resources/_gen/. The filename includes a hash, so browsers treat it as a new asset when the source changes.
To verify, inspect the generated HTML: the src attribute should contain a string like /images/photo.abcdef12345.jpg. Then check the resources/_gen/ folder for a file matching that hash.
3. Building a responsive srcset with multiple sizes
For true responsiveness, generate several widths and let the browser pick the best fit. The following snippet creates three widths (400, 800, 1200 px) and outputs a srcset attribute.
{{ $src := resources.Get "images/photo.jpg" }}
{{ $sizes := slice "400x" "800x" "1200x" }}
{{ $variants := slice }}
{{ range $sizes }}
{{ $v := $src | resize . | fingerprint }}
{{ $variants = $variants | append (dict "src" $v.RelPermalink "width" (printf "%sw" .)) }}
{{ end }}
Explanation of the template:
resources.Getfetches the original asset.- The
rangeloop creates a resized, fingerprinted version for each width. - We build a dictionary holding the URL (
src) and a width descriptor (width) forsrcset. - The
sizesattribute gives the browser hints about layout breakpoints; adjust these to match your CSS.
After rebuilding, view the page source. You should see an img tag with a srcset listing three URLs, each containing its own fingerprint hash. The resources/_gen/ directory will hold three corresponding files.
4. Trade‑offs and limitations
While Hugo Pipes eliminate external tooling, they come with considerations:
- Build time: Each transformation runs on every build unless the result is already cached. Very large source images (e.g., >5 MB) can noticeably increase
hugoexecution time. Keep source assets reasonably sized or useresources.Get"..." | fingerprintalone to avoid repeated resizing during development. - Format support: The underlying library handles JPEG, PNG, WebP, TIFF, and GIF. SVG cannot be processed through pipes; you must serve SVGs directly or use external tools.
- Cache management: Processed files accumulate in
resources/_gen/. Over time, especially after many image experiments, this folder can grow. Periodically runhugo --cleanDestinationor delete the folder to reclaim space; the cache will be regenerated on the next build.
To check that caching is working, note the build timestamp after the first run, then run hugo again without changing any images. The second build should be significantly faster, and the resources/_gen/ folder timestamps should remain unchanged.
Actionable closing
Start by installing Hugo extended, verify the version, and place a test image in assets/images/. Add the basic pipe snippet to a template, rebuild, and confirm the fingerprint appears in the HTML and the generated file exists under resources/_gen/. Once comfortable, expand to the responsive srcset pattern above, adjusting widths and sizes to match your design. Monitor build times; if they become a bottleneck, consider down‑sizing source images or limiting the number of variants during active development.
By leveraging Hugo Pipes you keep image optimization inside your site’s source, avoid extra build steps, and maintain a single source of truth for both content and presentation.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.