Hugo dev server CSS changes not updating in browser
Problem
When running hugo server in development mode, edits to a theme CSS file are detected by the dev server, but the browser continues to show the old CSS. Normal reload and hard reload do not apply the change. Restarting the Hugo dev server and then reloading the page makes the CSS change visible.
Observed log example:
|
|
This shows that Hugo detects the asset change and rebuilds, but the served/client-visible stylesheet does not update.
Relevant template code
|
|
Diagnosis
The likely cause is the use of:
|
|
This creates a synthetic Hugo resource from a string. It bypasses the normal Hugo Pipes resource graph for files in assets/. As a result, Hugo may detect that the source CSS file changed, but the resource cache/live-reload chain may not invalidate the synthetic stylesheet correctly.
This explains why:
- the dev server logs the CSS change;
build.cachebustersdoes not fix the issue;- browser reloads still show the old stylesheet;
- restarting the dev server clears the stale state and makes the new CSS visible.
resources.FromString is intended for resources created from generated string content. For an actual file under assets/, use resources.Get instead.
Corrected template code
Replace the current resources.FromString + readFile pattern with a normal asset lookup:
|
|
Do not include the theme directory prefix in resources.Get.
This file:
|
|
should be referenced as:
|
|
Theme assets are part of Hugo’s global asset lookup path.
Recommended dev-server command
Use this while testing the fix:
|
|
Purpose:
--disableFastRender: avoids partial rebuild behavior masking template/resource changes;--noHTTPCache: disables Hugo’s HTTP cache headers;--ignoreCache: avoids using configured caches during the build.
These flags are useful for diagnosis, but the primary fix is replacing resources.FromString with resources.Get.
Cachebusters
The cachebuster configuration is not expected to fix the current template because the pipeline input is not a normal asset resource. It is a string generated by readFile and wrapped with resources.FromString.
A normal cachebuster rule for theme assets should match paths relative to assets/, not paths starting with themes/<theme>/assets/.
Example:
|
|
But after switching to resources.Get, cachebusters may be unnecessary for plain CSS.
Verification
After changing the template, edit themes/reader/assets/css/theme.css, then check the served CSS directly:
|
|
Interpretation:
- If
curlshows the new CSS but the browser does not, the problem is browser-side caching, live-reload CSS injection, or a service worker. - If
curlstill shows the old CSS, the problem remains in Hugo’s resource/cache pipeline.
Additional check
If the CSS include is inside a cached partial, avoid this in development:
|
|
Use this instead:
|
|
A cached partial can keep emitting an old resource URL or stale generated markup.
Bottom line
This is a known class of Hugo dev-server/resource-cache behavior. In this specific case, the actionable fix is to stop using resources.FromString with readFile for a real theme asset and use resources.Get "css/theme.css" instead.
Relevant references:
- Hugo
resources.FromString: https://gohugo.io/hugo-pipes/resource-from-string/ - Hugo
resources.Get: https://gohugo.io/functions/resources/get/ - Hugo build cachebusters: https://gohugo.io/configuration/build/
- Related Hugo forum report: https://discourse.gohugo.io/t/resources-fromstring-breaks-resource-caching-reloading/52758
- Related Hugo issue for theme Sass/CSS refresh behavior: https://github.com/gohugoio/hugo/issues/12395