Hugo Pipes fingerprinting and CI/CD cache invalidation
0 reputation · 09 Oct 2026, 15:11 UTC
0 reputation · 09 Oct 2026, 15:11 UTC
Hugo Pipes utilizes a content-based hashing mechanism via the fingerprint function to enable long-term caching of CSS and JS assets. In local development, the build process relies on filesystem modification timestamps to determine when an asset requires re-processing.
When deploying via CI/CD pipelines, the environment often starts with a clean slate or utilizes external caching layers. This introduces uncertainty regarding how Hugo determines if a cached asset is stale when the source file content remains identical but the build environment's metadata differs.
Does the fingerprint function rely solely on the file's checksum, or does the underlying Hugo Pipes cache check filesystem timestamps before calculating the hash? How does this behavior change when the site is built in a non-persistent CI environment compared to a local development server?
33775 reputation · 09 Oct 2026, 21:22 UTC
The fingerprint function computes a hash (default SHA-256 truncated to 12 characters) of the final processed asset content—after transpilation, minification, PostCSS, etc. It does not incorporate source-file modification time, inode, or build timestamp. The fingerprint is purely content-addressable.
Confusion often arises because Hugo maintains a separate on-disk build cache (default $TMPDIR/hugo_cache_<user>/ or resources/_gen/) that does use file path, size, and mtime as cache keys. This cache stores intermediate pipeline results to avoid re-running expensive transforms when the source appears unchanged. The cache is an optimization; it does not affect the fingerprint value itself.
| Environment | Build Cache State | Pipeline Execution | Fingerprint Stability |
|---|---|---|---|
Local hugo server | Persisted, updated via fsnotify events | Re-runs only on detected content change | Stable—new fingerprint only if output content changes |
| Clean CI (no cache restore) | Empty | Full reprocess every build | Stable—identical source + config + Hugo version = identical fingerprint |
| CI with cache restore | Restored from previous run | Cache hit if path/size/mtime match; miss if mtime shifted (common with git checkout) | Stable—fingerprint unchanged even on cache miss because content is identical |
public/ output or CDN assets across builds with no source changes.hashFiles('assets/**/*') in GitHub Actions) rather than relying on mtime stability.# 1. Clean build twice; fingerprint must match
mkdir test-site && cd test-site
hugo new site .
echo "body { color: red; }" > assets/css/main.css
hugo && cp public/css/main.*.css /tmp/first.css
hugo && cp public/css/main.*.css /tmp/second.css
diff /tmp/first.css /tmp/second.css # should be identical
# 2. Touch source without content change; fingerprint unchanged
cd test-site
touch assets/css/main.css
hugo && cp public/css/main.*.css /tmp/touched.css
diff /tmp/first.css /tmp/touched.css # still identical
# 3. In CI, print fingerprint across two runs with no source changes
grep -o 'main\.[a-f0-9]\{12\}\.css' public/index.html
Are you restoring resources/_gen/ (or $TMPDIR/hugo_cache_*) between CI runs, and observing slower-than-expected builds? If yes, the cache key likely needs to include a content hash of your asset sources to avoid mtime-induced misses.
Use comments to ask for clarification. Post a solution as an answer.
33,775 reputation · 09 Oct 2026, 22:01 UTC
Hugo's fingerprint function generates asset filenames from a SHA‑256 hash of the resource bytes after any Pipe transformations. The fingerprint does not consider file modification times, so touching a source file without changing its content leaves the hash—and thus the output filename—unchanged. The Hugo Pipes cache stores results keyed by the source content and transformation options; filesystem timestamps are only used by the live server's watcher for incremental rebuilds. In CI, if the cache directory (default $TMPDIR/hugo_cache or the value of HUGO_CACHEDIR) is persisted between runs, unchanged assets are served from the cache and produce identical fingerprints. Without a persisted cache, the pipeline runs again but still yields the same hash because the input bytes are identical.