Configuration
This is the single home of site parameters. Every key the theme reads has a row in one of the tables below, giving its type, default and a one-line description, and linking to the guide that covers it. The guides give pasteable snippets and never repeat the definitions. Page-level parameters (front matter) are in Page parameters.
The tables are grouped by function, one ## each, and the anchors are
referenceable — for example /docs/customize/config/#sidebar. An empty
default column means the theme has no default: leave the key out and the
feature is off.
The layers of hugo.yml
An OINK site’s configuration has four kinds of key, and which layer you change depends on what you are changing:
| Layer | Examples | Who defines it |
|---|---|---|
| Hugo’s own top-level keys | baseURL title languages markup outputs taxonomies module |
Hugo itself; the behaviour is on gohugo.io |
Top-level params |
logo offline_search github_repo version page_width comments |
Site-level options the theme reads |
params.ui.* |
navbar_enabled sidebar_width_min typography pager_types |
The shell, navigation and reading interface |
params.<runtime> |
mermaid plantuml drawio markmap |
Each content runtime’s own switch and endpoint |
A minimal working configuration needs only the first two layers:
Configuration principles
-
The theme’s defaults are conservative; write only the keys you change. Interactive features (local search, image zoom, comments, feedback, the light/dark menu) are off by default, because the theme does not make policy for a site. Trimming a “complete configuration” leaves behind keys you never needed more readily than adding them as you go.
-
There is no theme master switch. There is no
oink.enabled, noparams.oink.*namespace, and no option that swaps between a “Docsy shell” and an “OINK shell”. A switch you cannot find on this page does not exist. -
An invalid value warns and falls back to the documented default.
params.ui.typography: solarizedreportsinvalid params.ui.typography "solarized" (allowed: technical | system) -- using "technical"and the site still builds;footer_style: thin,page_width: hugeandsection_index: gridbehave the same way. One typo therefore degrades one setting instead of serving HTTP 500 on every URL underhugo server. It cannot ship silently either: every publishing gate builds with--panicOnWarning, which turns the warning back into a hard failure. -
One warning keeps the value instead of dropping it. A
theme_colorthe theme reads as below AA body text (4.5:1) against its own canvas still ships — a custom canvas or a brand mandate is the author’s call — but says so, and prints theignoreLogsid that silences it. Treat it as advice, not a rejection: the fix is either a darker color or one line of configuration, and the publishing gate stops the build until you choose. Only an unparseable hex is dropped outright, and that one falls back to the default palette like every other invalid value. -
The theme itself never stops the build. Its templates contain no
errorfat all: every invalid value takes the warn-and-fall-back path above. A feature needing an external endpoint — PlantUML, Draw.io, Algolia — warns and stays off when the endpoint is missing, because the theme never connects to a public service on your behalf. An incomplete upstream attribution warns and omits the whole notice, because a partial one reads exactly like a complete one. What does stop a build comes from Hugo rather than the theme: a content reference that resolves to nothing, and a Hugo older thanmodule.hugoVersion.min.
Page-level override precedence
Hugo’s .Param lookup lets most parameters be overridden per page, highest
precedence first:
- The page’s own front matter;
cascadein an ancestor section’s_index.md(nearer wins);- Site
params.
Drop the ui. prefix when writing it in front matter. The site’s
params.ui.scroll_spy is simply scroll_spy on a page. A ui: block in front
matter is read by nobody and reported by nobody, so a setting that seems to have
no effect is worth checking against
Page parameters first.
A cascade sets a whole subtree at once:
Overrides are for real differences in content. Rebuilding a visual system page by page tends to fall out of step at the next theme upgrade.
The three Goldmark prerequisites
Hugo does not merge a theme module’s markup configuration into the site,
so these three must be in the site’s own hugo.yml, or attribute lines,
component HTML and mathematics all stop working:
Without attribute.block, {.fields}, {.steps} and {caption=…} render as
literal text; without passthrough, \(x\) never becomes a formula; without
unsafe, the structure of steps and cards is escaped away.
renderer.unsafe: true also lets raw HTML in Markdown through. It is meant for
trusted authors, not as a submission filter. Where content comes from untrusted
sources, the review belongs in the contribution process.
Site identity and brand
Hugo’s own top-level keys:
Theme parameters:
params.logo, ,- Brand mark; may point at an
assets/resource or astatic/path — see Brand and appearance params.copyright,- A string renders as Markdown; a map takes
authors,from_yearandto_year(presentmeans this year) params.ui.theme_color,#rgb/#rrggbbhex tinting the shell’s accent grounds; prose links and inline code are unaffected — see Brand and appearance
There is no favicon parameter: the theme scans static/ for conventional names
(favicon.ico, favicon.svg, favicon-NxN.png, apple-touch-icon.png,
apple-touch-icon-NxN.png) — see
Brand and appearance.
Shell types and section roots
The shell follows the page type, not the path. Documentation can live in any
directory, with a cascade giving it type: docs.
params.ui.shell_types, ,- Which types use the reading shell with a sidebar — see Layouts and page types
params.ui.docs_section, ,- The documentation section’s root directory name, used for navigation resolution only
params.ui.docs_sidebar_root, ,- With
section, a docs page’s sidebar roots at the documentation section; withhome, at the site home. An invalid value warns and falls back params.ui.quick_links, ,- Top-level menu identifiers listed by the command palette on an empty query — see Command palette
params.ui.sidebar_root_enabled, ,- Allows a subsection to become its own sidebar tree with
sidebar_root_for: self
Blog
Seven keys shape a blog section. They apply to the section named by
params.ui.blog_section, and each can be overridden per section through front
matter or a cascade on the blog root.
params.ui.featured_image, ,- How an article renders its own featured image:
nonerenders nothing,bannerframes it above the title in a 16:9 figure,washlays it behind the article header at a tenth of its opacity,heropaints it as the shell’s own full-bleed backdrop and moves the opening down — on single pages and section indexes alike. The image is whichever one the page already shares in its card andog:image, so the two cannot disagree. An article with no image renders nothing in any mode params.ui.blog_index, ,- The blog section’s list page:
listis the row list,cardsa grid of content cards with a 16:9 lead image, the date and section line, and a three-line summary,tableone compact row per post — the whole section at once, with no year groups and no pagination. Year grouping, pagination andmanual_linkbehave the same inlistandcards params.ui.blog_index_columns, ,- Column count when
blog_index: cards; two between the md and xl breakpoints, one below md, whatever this says params.ui.blog_index_size, ,- Posts per page on a
listorcardsindex; thetableform always shows everything. Twelve divides by two, three and four, so no card row is left short params.ui.blog_index_toggle, ,- Lets a reader cycle the index through list, cards and table from the index toolbar. Off by default, because it puts all three forms in the document — the hidden ones load no images, but their markup is real
Article authorship and series are taxonomies rather than parameters — see Taxonomies and Writing a blog.
Navbar and footer
The fat footer’s column data comes from data/footer/<language>.yaml rather
than from a parameter — see
Navigation and menus.
Sidebar
params.ui.sidebar_cache_limit, ,- Above this page count the site reuses shared navigation markup, and the browser restores the active state
params.ui.sidebar_icon_policy, ,- Icon density:
alleverywhere,groupsonly on the root and nodes with children,nonenowhere. An invalid value warns and falls back toall params.ui.sidebar_headings, ,type: bookonly: expands a heading branch under the current sidebar row; an integer from 2 to 4, andtruemeans 2
How to use the sidebar is in
Layouts and page types; the tree itself comes
from the shape of content/ — see
Organizing content.
Table of contents
The outline’s levels come from Hugo’s own configuration; the theme controls only the tracking behaviour:
Hide the outline on one page with the front matter notoc: true — see
Page parameters.
Pager and page end
The page-end components are in a fixed order — share → feedback → page information → pager → comments — and each has its own switch; backlinks sit in the right rail beside the table of contents.
params.ui.pager_types, ,- Which types show previous / next; a page opts out with the front matter
pager: false. An unknown type warns and is dropped params.ui.annotation, ,- The “last modified” and provenance block at the end of the body; the upstream attribution line is driven by the page’s
upstream_linkfamily — see Page parameters params.ui.backlinks, ,- Lists the pages that link to this one as a “Backlinks” group in the right rail beside the table of contents, derived at build time from ordinary links — see Navigation and menus
Search and command palette
Local search is off by default, and the command palette appears only once it is
on (the navbar magnifier, Cmd/Ctrl with K, /, \).
params.offline_search, ,- Generates one local index per language and enables the command palette — see Search
params.offline_search_on_serve, ,- Builds the index under
hugo servertoo, so the preview behaves like production; setfalseon a very large site to speed up local rebuilds params.offline_search_index, ,- Index scope, cumulative:
title,heading,summary,content. An invalid value warns and usescontent params.ui.command_palette.commands, ,- Custom commands, each with either
urlor a built-inaction— see Command palette
A custom command record accepts seven keys only — id, title, description,
icon, keywords, url, action — and id must match ^[a-z][a-z0-9_-]*$
and must not collide with a built-in action ID. Per-language titles go under
languages.<lang>.params.ui.command_palette.commands.
Keyboard
Image zoom
Which images become zoom candidates is in Images.
Typography
Use params.ui.fonts when the faces already exist on the reader’s system or the
site has declared them with @font-face. Bundling font files and changing
lower-level typography still use the SCSS/CSS entry points — see
Brand and appearance.
Comments and feedback
params.comments.enable, ,- The site-level comment switch; a page overrides it with the front matter
comments— see Comments params.comments.giscus.term,- The discussion title or number when
mappingisspecificornumber; the attribute is omitted when unset params.comments.giscus.lang, ,- The giscus interface language. Unset, a Chinese site resolves
zh-CN/zh-TW/zh-HK, other languages take the base language code, and anything giscus does not support falls back toen params.comments.giscus.ariaLabel, ,- The
aria-labelon the comment container; the default is English, so a multilingual site writes one per language params.comments.giscus.errorMessage, ,- Text shown when loading fails; the default is English, so a multilingual site writes one per language
Missing any one of the four required giscus values leaves the comment section unrendered: no error, and nothing appears.
Repository links and page information
params.github_repo,- The content repository URL, resolving “edit this page”, “view history”, “create child page” and “open a documentation issue” — see Repository links and page info
params.github_project_repo, ,- The product repository URL, for “open a project issue” and the navbar GitHub entry
params.github_url, ,- Removed; write
params.github_repo. The migration registry that used to name the replacement is gone, so an old key is now simply an unread key params.ui.lastmod_commit, ,- What follows “last modified”:
subjectthe commit subject,hashthe short hash,nonenothing. An invalid value warns and falls back params.images, ,- The site-level social card: fills
og:imagewhen a page has no image of its own. Metadata only; never rendered as a list thumbnail params.upstream_source, ,- Default
data/upstreamsrecord name for pages that declareupstream_link; page front matter can override it
Content runtimes
Mermaid, KaTeX, ECharts, Infographic, Asciinema, Swagger UI and Redoc are detected from the content and load only where a page uses them, and only in that page’s HTML output; they have no site switch. Only these need a switch or an external endpoint:
params.markmap, ,- Enables the mind map fence site-wide — see Markmap
params.mermaid,- Configuration passed to
mermaid.initialize(); keys are lowercase, and dark mode overridesthemeautomatically params.plantuml.enable, ,- Enables the PlantUML fence — see PlantUML
params.plantuml.svg_image_url,- The PlantUML service’s SVG endpoint; required when enabled, and its absence warns and leaves PlantUML off
params.drawio.enable, ,- Enables the edit button on
.drawio.svgimages — see Draw.io params.drawio.drawio_server,- The Draw.io editor address; required when enabled, and its absence warns and leaves Diagrams.net off
Mathematics needs no parameter, only the
passthrough prerequisite.
Output formats
The theme declares its custom output formats but does not enable them for a
site: request what you want under outputs. Expensive aggregate and
machine-readable outputs remain explicit opt-ins.
| Format | Output | Description |
|---|---|---|
HTML |
index.html |
The interactive form; required |
markdown |
index.md |
Each page’s plain Markdown twin, which “copy Markdown” and “view source” depend on — see AI-agent support |
LLMS |
llms.txt |
A plain-text format the theme declares, usually attached to home only |
LLMSFULL |
llms-full.txt |
A top-level section opt-in: the same per-page Markdown concatenated in sidebar reading order, one bundle per language |
NAVJSON |
navigation.json |
A home opt-in: the sidebar/pager navigation authority serialized once per language, validated by schema/nav.v1.schema.json |
print |
_print/index.html |
The whole-section print page the theme declares — see Print |
BookManifest |
book.json |
A Book-root opt-in JSON handoff for the EPUB/PDF packaging tools; it is not itself an ebook |
RSS |
index.xml |
Hugo’s own; attach it to section so every section has a feed |
LLMSFULL and BookManifest are enabled in the relevant top-level section’s
front matter rather than globally. NAVJSON belongs on outputs.home. The
complete examples and constraints are in AI-agent support
and Books.
Two parameters for print output:
Languages and versions
Languages are defined with Hugo’s own languages block, and the theme only
reads the translation relationships it establishes:
Paired files, anchor alignment and fallback for untranslated pages are in Languages.
Version parameters:
params.version,- The identifier of this site variant, which need not be a Git ref — see Versions
Miscellaneous
taxonomies,- Hugo’s own: enables
tag: tags/category: categories— see Taxonomies services.googleAnalytics.id,- Hugo’s own: the analytics script is injected in production builds only — see Analytics and SEO
Editor completion via generated schemas
The theme ships two generated JSON Schemas under its schema/ directory:
site-params.schema.json for a site’s hugo.yaml and
front-matter.schema.json for page front matter. They are projections of the
theme’s own hugo.yaml defaults (with the comment documentation as hover
text) and its parameter-scan registry; the theme’s CI regenerates them and
fails on drift, so they can never disagree with the theme you have pinned.
With the VS Code YAML extension, map the site schema in your settings:
Pin the URL to your release tag instead of main to match your go.mod pin.
Front matter completion depends on your Markdown tooling; point it at
front-matter.schema.json the same way. The front-matter schema deliberately
omits type constraints, because keys like share and theme_color accept a
bare-boolean opt-out beside their ordinary type.
Verifying a configuration change
Run a strict build after changing configuration:
It passes only when the output reads Total in … with no ERROR and no WARN.
Common errors and what they mean:
| Error fragment | Cause |
|---|---|
invalid params.ui.typography |
The presets are technical and system |
invalid footer_style … (allowed: fat | slim | none) |
A bad footer style; the error names the page |
invalid page_width … (allowed: normal | wide | full) |
A bad page width |
invalid params.ui.section_index … (allowed: list | cards) |
A bad section index style |
invalid params.offline_search_index |
The scopes are title, heading, summary, content |
params.plantuml.enable requires an explicit params.plantuml.svg_image_url |
PlantUML enabled with no endpoint |
params.drawio.enable requires an explicit params.drawio.drawio_server |
Draw.io enabled with no server address |
params.search.algolia requires explicit appId, apiKey, and indexName |
All three Algolia values are required |
params.ui.image_zoom must be a boolean |
Written as the string "true" |
theme_color … is not a #rgb or #rrggbb hex color |
The value is not a hex color; the default palette is kept |
theme_color … reads at about N:1 against the theme's … canvas |
Advisory: the color ships, and the message prints the id that silences it |
theme_color_dark … has no theme_color to pair with |
The dark half was set without a valid theme_color; it is ignored and the default palette is kept in both modes |
command … must define exactly one of url or action |
A custom command gave both url and action, or neither |
invalid params.ui.sidebar_icon_policy …; using all |
Only a warning, but the value is misspelled |
A configuration change also needs at least three checks: one page in each
language, a page with no translation to see the fallback, and the links under
the production baseURL (easy to miss on a subpath deployment).
The theme’s declared Hugo floor is 0.160.1. OINK’s continuous test toolchain
is pinned to Hugo Extended 0.165.0; configuration changes are tested once
with that pinned version instead of against a version matrix:
The floor is declared in the theme’s hugo.yaml and theme.toml, and a site’s
own module.hugoVersion.min should agree with it. It remains a consumer
compatibility declaration, not a second routine CI test leg.
Related
- Brand and appearance — site name, logo, colours, fonts
- Navigation and menus — navbar menu, page actions, footer
- Layouts and page types — shell, sidebar, table of contents
- Page parameters — the full front matter table
- Troubleshooting — locating a build failure