Docs
Upgrading to Hinode V3
Note
Still on Hinode v1 or earlier? Check out Upgrading to Hinode V2 first and work your way up one major version at a time.
Hinode
v3.0.0
is a coordinated release of the theme and its companion modules, known as the v3 module generation. At its heart is a redesigned argument validation engine in mod-utils v6: arguments passed to shortcodes, partials, and content blocks are now validated recursively at any nesting depth, with clearer diagnostics and substantially faster builds. The engine keeps full compatibility with existing call sites, so most sites upgrade by updating module versions alone. This guide targets users of the
Hinode template
running a v2-compatible site. Please use
GitHub discussions
when encountering any challenges, or the
issue tracker
for bug reports.
Meeting the Prerequisites
The prerequisites are unchanged from v2: Hugo Extended 0.146.0 or later, and the Dart Sass transpiler. If your site pins an older hugo-bin or hugo-extended package, bump it to a release that provides Hugo 0.146+.
Updating the Module Imports
Hinode v3 uses a new Go module path (hinode/v3) and pins a coordinated set of module majors. Update the import paths in config/_default/hugo.toml for every module your site uses:
| Module | Version | Import path |
|---|---|---|
| hinode | v3.0.1 | github.com/gethinode/hinode/v3 |
| mod-utils | v6.4.1 | github.com/gethinode/mod-utils/v6 |
| mod-blocks | v2.0.2 | github.com/gethinode/mod-blocks/v2 |
| mod-fontawesome | v6.0.0 | github.com/gethinode/mod-fontawesome/v6 |
| mod-flexsearch | v5.0.0 | github.com/gethinode/mod-flexsearch/v5 |
| mod-leaflet | v3.0.0 | github.com/gethinode/mod-leaflet/v3 |
| mod-lottie | v3.0.1 | github.com/gethinode/mod-lottie/v3 |
| mod-mermaid | v5.0.0 | github.com/gethinode/mod-mermaid/v5 |
| mod-simple-datatables | v4.0.0 | github.com/gethinode/mod-simple-datatables/v4 |
| mod-hanko | v3.0.0 | github.com/gethinode/mod-hanko/v3 |
| mod-hubspot | v4.0.0 | github.com/gethinode/mod-hubspot/v4 |
| mod-llm | v2.0.0 | github.com/gethinode/mod-llm/v2 |
| mod-bootstrap-icons | v2.0.0 | github.com/gethinode/mod-bootstrap-icons/v2 |
| mod-flaticon | v2.0.0 | github.com/gethinode/mod-flaticon/v2 |
Modules not listed, such as mod-bootstrap, mod-csp, and mod-katex, are unaffected and keep their current versions.
As an example, update the Hinode import as follows:
Before:
[[module.imports]]
path = "github.com/gethinode/hinode/v2"After:
[[module.imports]]
path = "github.com/gethinode/hinode/v3"Next, refresh the module dependencies and vendor folder:
hugo mod get github.com/gethinode/hinode/v3@v3.0.1
npm run mod:tidy
npm run mod:vendorImportant
Adopt the generation together: update Hinode and all listed modules in a single step. Adding a single v3-generation module to a v2 site switches the entire site to the new validation engine through Hugo’s module mounts — technically compatible, but easy to do by accident and confusing to debug.
Reconciling Customized Templates and Styles
The steps above cover sites that consume Hinode as-is. If your project overrides Hinode by shadowing its files — placing a copy of a layout, partial, or SCSS file at the same mount path so Hugo prefers yours — those copies are pinned to the version you forked from and do not follow the module upgrade. A shadowed file that built cleanly under v2 can reference partials, arguments, or variables that moved or changed in v3.
The reliable way to reconcile a shadow is to diff it against the vendored v3 copy and re-apply your customizations onto the v3 version, rather than the reverse:
# run from your project root, after vendoring the v3 modules
diff assets/scss/common/_variables-dart.scss \
_vendor/github.com/gethinode/hinode/v3/assets/scss/common/_variables-dart.scssShadowed SCSS Variables
Note
A missing SCSS variable surfaces as a build error inside a vendored component, not your own file — for example
Undefined variablein_vendor/.../hinode/v3/assets/scss/components/_table.scss. The fix belongs in your shadow ofcommon/_variables-dart.scss, not in the file the error points to.
If you shadow common/_variables-dart.scss to override Bootstrap variables, add the variables v3 introduced so the vendored components can resolve them:
$main-breakpoint: h.$main-breakpoint;
$padding-x: h.$padding-x;
$padding-y: h.$padding-y;
$theme-mode-transition: background-color .5s ease-in-out, color .5s ease-in-out, border-color .5s ease-in-out !default;The SCSS Entry Point
Hinode selects the stylesheet entry point from your transpiler: app-dart.scss for Dart Sass and app.scss for libsass. If your project shadows the entry point — often a leftover from an early Dart Sass workaround — re-sync its import list with the vendored v3 copy. In v3 the entry adds the lightbox component and imports scrollbar ahead of the components so they can @include its mixin. Unless you genuinely customize the import list, the simplest fix is to remove your shadow and let the vendored entry point run; it still picks up your shadowed _variables-dart.scss and theme/ files.
Moved Partials and Changed Signatures
Custom layouts that call Hinode partials directly may need small updates. The most common in v3:
| Call site (v2) | v3 |
|---|---|
partial "assets/navbar-item.html" |
partial "assets/helpers/navbar-item.html" — and the menu argument is deprecated in favor of menu-entry |
partial "page/blocks.html" . |
partial "page/blocks.html" (dict "page" . "embed" true) |
partial "assets/sidebar.html" (docs layout) |
partial "page/sidebar-cached.html" |
partial "assets/image.html" (dict "src" …) |
add "page" $page — the global-context fallback is deprecated and logs a warning |
When passing a menu that may be empty, hand the partial a nil rather than an empty string; the v6 engine type-checks the argument.
Exercise the Paths Your Own Content Does Not
A clean build of your site does not exercise override code hidden behind conditionals. Force each path with throwaway content before you trust the upgrade:
- a footer menu entry with a child (a childless entry never reaches the item partial),
- a
type: docssection with one page, to render the docs layout, - a page with
tagsset, to render tag output.
Build, confirm there are no warn-invalid-arguments warnings, then remove the temporary content. This matters most for shared themes consumed by other sites, where the override paths are not reachable from the theme repository’s own content.
Reviewing the Build Output
The new engine validates arguments recursively and reports every problem it finds, not just the first. Newly detectable problems — wrong-typed values, unknown nested attributes, and excess positional arguments — surface as warnings in this generation. They will be promoted to errors in a future major release, so use the quiet period to clean up your content and custom templates.
The most common warning after upgrading is an empty string passed where an argument should simply be omitted:
# triggers a warning: empty string is not a valid select value
navigation:
color: ""Remove the key instead of assigning an empty value.
Two behavioral refinements are worth knowing when reviewing custom templates:
- Argument defaults defined in the schema are now applied consistently, including
falseand0values that previous releases silently skipped. - When a component declares both a current argument and a deprecated alias (such as
show-previewandshow_preview), the current argument always takes precedence and deprecated aliases no longer receive defaults.
Rendered output is intended to be identical to v2. The generation was validated against Hinode’s full block and component library; if you spot a visual difference after upgrading, please open an issue.
Updating CloudCannon Configurations
If your site uses
CloudCannon
with the setup-cloudcannon-cms utility, update any expose globs that reference vendored module paths, for example:
# before
- _vendor/github.com/gethinode/mod-utils/v5/layouts/**/*.html
# after
- _vendor/github.com/gethinode/mod-utils/v6/layouts/**/*.htmlRegenerate the Bookshop configuration afterwards (npm run config) and verify visual editing on your connected site.
Adopting the New Argument API (Optional)
Sites and themes with custom shortcodes or partials can keep using InitArgs.html — it remains fully supported as a compatibility shim. When you are ready, migrate to the new Args.html partial for a cleaner contract: a separated result envelope (args, err, errmsg, warnmsg, defaulted), camelCase argument keys, and strict validation. See the
mod-utils documentation
for the full API reference and migration notes.