Generate and Install Hugo's Chroma CSS Safely
You will generate a standalone CSS stylesheet for Hugo's class-based Chroma highlighting, check its contents, and install it as a new asset without destroying an existing stylesheet. Allow about fifteen minutes. You need Hugo 0.123.7 or a nearby release, a Hugo site that uses class-based highlighting, and write access to the site's asset directory.
The route
Jump straight to the step you need, or tick off Done means at the end.
This guide describes the installed package on this machine: Hugo 0.123.7, built as the Ubuntu package 0.123.7-1ubuntu0.3+esm2. Later Hugo releases have changed some option names, so read the installed help if your version differs.
1. Check the command and the highlighting mode
First confirm that the command being run is the one from your installed package. This is an ordinary read-only check and does not need elevated privileges:
$ command -v hugo
/usr/bin/hugo
$ hugo version
hugo v0.123.7+extended linux/amd64 BuildDate=2026-03-17T19:51:14Z VendorInfo=ubuntu:0.123.7-1ubuntu0.3+esm2
hugo gen chromastyles is useful when your configuration leaves markup.highlight.noClasses disabled. In that mode Hugo emits classes such as chroma and expects a matching stylesheet. If you use inline styles instead, generating this file is unnecessary.
Check the setting from the site root. The exact command depends on your configuration format, so inspect it without editing:
$ rg -n 'noClasses|highlight' hugo.yaml config/ 2>/dev/null
config/_default/markup.yaml:4: noClasses: false
Your path and output may differ. If the search finds noClasses: true, stop here unless you are deliberately changing the highlighting design. This command does not alter the site configuration.
2. Choose a style and generate a temporary file
The default style in this installed version is friendly. Use an explicit style in scripts so a future default change cannot silently alter the generated CSS. Hugo writes the stylesheet to standard output, so redirect it to a temporary file inside the site or a private temporary directory.
$ tmp_css=$(mktemp /tmp/hugo-chroma.XXXXXX.css)
$ hugo gen chromastyles --style monokai > "$tmp_css"
$ printf 'exit status: %s\n' "$?"
exit status: 0
The value for --style is a Chroma style name. The official Hugo style gallery is the practical place to select one. Common names include friendly, monokai, github and dracula, but check the gallery or your installed command before putting a name into automation.
Checkpoint: make sure the command produced CSS rather than an empty file or an error message:
$ wc -c "$tmp_css"
4537 /tmp/hugo-chroma.A1b2C3.css
$ sed -n '1,4p' "$tmp_css"
/* Background */ .bg { color: #f8f8f2; background-color: #272822; }
/* PreWrapper */ .chroma { color: #f8f8f2; background-color: #272822; }
/* Other */ .chroma .x { }
/* Error */ .chroma .err { color: #f92672 }
The byte count and colours depend on the selected style. The useful checks are a zero exit status, a non-zero file size, and selectors beginning with Chroma's classes.
3. Add line highlighting or line-number colours only when needed
--highlightStyle and --linesStyle do not select another named theme. They accept Chroma style elements for highlighted lines and line numbers. For example, this adds a pale background to highlighted lines and a grey foreground colour to line numbers:
$ hugo gen chromastyles \
--style monokai \
--highlightStyle 'bg:#ffeeaa' \
--linesStyle '#888888' \
> "$tmp_css"
$ rg -n 'LineHighlight|LineNumbers' "$tmp_css"
9:/* LineHighlight */ .chroma .hl { background-color: #ffeeaa }
11:/* LineNumbers */ .chroma .ln { white-space: pre; -webkit-user-select: none; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #888888 }
Keep these options separate from --style. Passing a theme name such as monokai to --highlightStyle is not the same operation and can fail with an unknown style element error. If you do not need special line treatment, omit both options.
4. Check the output before changing the site
Inspect the selectors and search for an error string before installing the file:
$ test -s "$tmp_css" && echo 'stylesheet is non-empty'
stylesheet is non-empty
$ rg -n '(^| )\.chroma|LineHighlight|LineNumbers' "$tmp_css" | head
1:/* Background */ .bg { color: #f8f8f2; background-color: #272822; }
2:/* PreWrapper */ .chroma { color: #f8f8f2; background-color: #272822; }
9:/* LineHighlight */ .chroma .hl { background-color: #ffeeaa }
Do not install a file if the exit status is non-zero. A failed command can leave a partial file when shell redirection is used. Keep the old asset until the replacement has passed these checks.
5. Install atomically without overwriting a working asset
Replace the placeholder paths below with your real site directory. This changes site state, but it does not require sudo when you own the Hugo project:
$ site_css='static/css/syntax.css'
$ install -D -m 0644 "$tmp_css" "$site_css.new"
$ if [ -e "$site_css" ] && [ ! -e "$site_css.bak" ]; then cp --preserve=all "$site_css" "$site_css.bak"; fi
$ mv "$site_css.new" "$site_css"
$ rm -f "$tmp_css"
$ test -s "$site_css" && echo "installed: $site_css"
installed: static/css/syntax.css
The backup command may report nothing when the asset did not exist. The mv happens only after the new file has been written. If the new CSS causes a problem, restore the backup with mv "$site_css.bak" "$site_css". Do not run that restore command unless the backup exists and you have checked its path.
Do not delete the backup as part of a blind deployment. Once you have rendered and checked the site, remove it deliberately with rm -- "$site_css.bak" if you no longer need recovery. That deletion is irreversible.
6. Build the site and diagnose failures
Run Hugo from the site root and check that the generated pages still contain the expected Chroma classes:
$ hugo --quiet
$ rg -n 'class="[^"]*chroma|class="chroma' public/ | head
public/posts/example/index.html:42:<div class="highlight"><div style="color:#f8f8f2;background-color:#272822" class="chroma">
The exact HTML varies with the Hugo template and highlighting options. If the style name is rejected, use the installed help and the official style gallery to choose a supported Chroma style. If the CSS is present but code still looks unstyled, check that the stylesheet is included by the final page and that its selectors match the classes Hugo emits. A successful stylesheet generation does not prove that your template loads the file.
If you need to undo this guide, restore "$site_css.bak" as described above and rebuild. No elevated privileges or service restart are part of the generation command.
Done means
- Hugo's installed version and the site's
noClassessetting were checked. - A named Chroma style generated a non-empty CSS file with exit status 0.
- Line options, if used, were supplied as style elements rather than theme names.
- The existing stylesheet was preserved until the replacement had been checked.
- A Hugo build completed and the output contains the classes targeted by the stylesheet.