v0.161.0
gohugoio/hugov0.161.0Apr 28, 2026by bep
AI Summary
Introduces nested CSS variables, a flexible slice-based permalinks configuration, and a new filename identifier scheme for content and layout files.
Key Highlights
- Nested vars support in CSS/Sass using `hugo:vars`
- Slice-based permalinks config using PageMatcher target
- Flexible filename identifiers (role_, version_, etc.)
- Harden Node tool execution with --permission flag
New Features
- Nested vars in CSS/Sass
- Slice-based permalinks
- Flexible filename identifiers
Full Release Notes
This release contains two security hardening fixes:
* We now run the Node tools PostCSS, Babel and TailwindCSS, by default, with the `--permission` flag with the permissions defined in [security.node.permissions](https://gohugo.io/configuration/security/). This means that you need Node >= 22 installed and that `css.TailwindCSS` now requires that the Tailwind CSS CLI must be installed as a Node.js package. The [standalone executable](https://github.com/tailwindlabs/tailwindcss/releases/latest) is no longer supported
* We have made the defaults in [security.http.urls](https://gohugo.io/configuration/security/#httpurls) more restrictive.
But there are some notable new features, as well:
## Nested vars support in css.Build and css.Sass
A practical example in `css.Build` would be to have something like this in `hugo.toml`:
```toml
[params.style]
primary = "#000000"
background = "#ffffff"
[params.style.dark]
primary = "#ffffff"
background = "#000000"
```
And in the stylesheet:
```css
@import "hugo:vars";
@import "hugo:vars/dark" (prefers-color-scheme: dark);
:root {
color-scheme: light dark;
}
```
## Slice-based permalinks config
The `permalinks` configuration is now much more flexible (the old setup still works). It uses the same [target](https://gohugo.io/configuration/cascade/#target) matchers as in the `cascade` config, meaning you can now do:
```yaml
permalinks:
- target:
kind: page
path: "/books/**"
pattern: /books/:year/:slug/
- target:
kind: section
path: "/{books,books/**}"
pattern: /libros/:sections[1:]
- target:
kind: page
pattern: /other/:slug/
```
The above example isn't great, but it at least shows the gist of it.
## A more flexible scheme for identifiers in filenames
What we had before was e.g. `content/mypost.en.md` which told Hugo that the content files was in English. With the new setup you could also name the file `content/mypost._language_en_.md`. This alone doesn't sound very useful, but this allows you to use more prefixes:
| Prefix | Description | Relevant for |
| --------------- | ------------- | ------------------------- |
| language_ | Language | Content and layout files. |
| role_ | Role | Content and layout files. |
| version_ | Version | Content and layout files. |
| outputformat_ | Output format | Layout files. |
| mediatype_ | Media type | Layout files. |
| kind_ | Page kind | Layout files. |
| layout_ | Layout | Layout files. |
## All Changes
* langs/i18n: Fix translation lookup when using language variants 72b85d5f @jmooring #7982
* create: Fix non-deterministic conflict detection in hugo new content 6436deb3 @jmooring #12602 #12786 #14112 #14769
* commands: Fix environment isolation for configuration settings 1eea9fba @jmooring #14763
* Fix filename dimension identifiers (_role_X_, _version_X_) to replace mount config 8d6145f3 @bep #14756
* Fix it so we never auto-fallback to page resources in other roles/versions 97477242 @bep #14749 #14752
* css: Support nested hugo:vars/<name> imports 7622dd86 @bep #14705
* github: Update GitHub actions versions 0814059b @bep #14810
* hugolib: Do not render aliases if the page is not rendered 8920d56e @jmooring #14807
* langs/i18n: Improve default content language fallback 633cc772 @jmooring #14243
* helpers: Remove unused code 4c40c6d5 @bep
* common/constants: Remove unused consts d2594db6 @bep
* common/paths: Remove unused code ab2de51e @bep
* tests: Update Ruby setup action to v1.305.0 75f61832 @jmooring
* langs: Use Language.Locale as primary localization key 1b7495bc @jmooring #9109
* config/security: Add "! " negation to Whitelist, harden default http.urls 79f030be @bep #14792
* Harden Node tool execution with --permission flag a54c398b @bep #7287
* tpl/collections: Honor the Eqer interface in where comparisons f5fce935 @bep #14777
* modules: Ignore non-require blocks in go.mod rewrite 4169c1f7 @bep #14783
* Replace the concurrent map with an identical upstream version 7574e35b @bep
* Add slice-based permalinks config with PageMatcher target 017a7cd6 @bep #14744
* commands: Add missing import e3413d92 @bep
* Revert "common/hugo: Deprecate extended and extended_withdeploy editions" b01cc147 @bep #14771
* Adjust the SECURITY.md slightly 8ee19ff9 @bep
* resources/page: Add passing test for Issue #14325 0d58e428 @jmooring
* Add a more flexible filename identifier scheme that also allows setting roles and versions (#14754) ce2a156a @bep #14750
* common/hugo: Deprecate extended and extended_withdeploy editions a17bdbc5 @jmooring #14696
* parser/pageparser: Add a parser fuzz test 8f94d65c @bep
* Replace deprecated .Site.Sites/.Page.Sites with hugo.Sites intests 90d8bf34 @bep
* agents: Add a note about having the issue ID in test names bbb42b5a @bep
* build(deps): bump github.com/getkin/kin-openapi from 0.135.0 to 0.137.0 d4ae662d @dependabot[bot]
* build(deps): bump github.com/mattn/go-isatty from 0.0.21 to 0.0.22 9ede5fb9 @dependabot[bot]
* build(deps): bump github.com/tdewolff/minify/v2 from 2.24.12 to 2.24.13 833a878e @dependabot[bot]
* build(deps): bump github.com/magefile/mage from 1.17.1 to 1.17.2 4c03129f @dependabot[bot]
* deps: Upgrade github.com/bep/imagemeta v0.17.1 => v0.17.2 080970bc @bep
* build(deps): bump github.com/aws/aws-sdk-go-v2/service/cloudfront (#14789) 896bc89a @dependabot[bot]
* build(deps): bump github.com/mattn/go-isatty from 0.0.20 to 0.0.21 (#14788) 100dde53 @dependabot[bot]
* build(deps): bump github.com/bep/mclib (#14787) bdebb797 @dependabot[bot]
* build(deps): bump google.golang.org/api from 0.267.0 to 0.276.0 52123ae2 @dependabot[bot]
* build(deps): bump github.com/aws/aws-sdk-go-v2 from 1.41.5 to 1.41.6 38b8afdc @dependabot[bot]
* build(deps): bump github.com/getkin/kin-openapi from 0.134.0 to 0.135.0 (#14781) 92766600 @dependabot[bot]
* build(deps): bump github.com/bep/goportabletext from 0.1.0 to 0.2.0 (#14779) 790f4084 @dependabot[bot]
* build(deps): bump golang.org/x/image from 0.38.0 to 0.39.0 (#14780) de6955ba @dependabot[bot]
* deps: Upgrade github.com/bep/imagemeta v0.17.0 => v0.17.1 (#14775) a77bd527 @bep #14758
* build(deps): bump golang.org/x/tools from 0.43.0 to 0.44.0 547ab29c @dependabot[bot]
* build(deps): bump github.com/evanw/esbuild from 0.27.4 to 0.28.0 9a5c7e0d @dependabot[bot]
* build(deps): bump github.com/aws/aws-sdk-go-v2 from 1.41.1 to 1.41.5 6613b08e @dependabot[bot]
* build(deps): bump github.com/pelletier/go-toml/v2 from 2.2.4 to 2.3.0 582c26ef @dependabot[bot]
* build(deps): bump github.com/tdewolff/minify/v2 from 2.24.11 to 2.24.12 a4f2a8a5 @dependabot[bot]