From scratch and other install methods
This is the manual alternative to the recommended
OINK Starter. It builds a minimal site in an empty
directory: a small hugo.yml plus one hugo mod get gives a single-language
site you can preview. The cost is that the home page, example content,
deployment workflow, and every component usage are yours to assemble.
For an existing Hugo site, use the short integration path below. For an existing Docsy site, see Upgrade.
The second half weighs four install methods: Hugo Module, Git submodule, offline archive, and pinned source copy. OINK 1.1.0 uses Go 1.27 and Hugo Extended 0.165.0 for release validation. The theme’s lower declared compatibility floor is for existing sites that deliberately retain an older toolchain.
Add OINK to an existing site
Work on a branch with the site’s current configuration and content preserved.
Skip hugo new site and keep the existing configuration filename.
- If the site has no
go.mod, runhugo mod initwith your repository’s module path. Otherwise keep the existing module declaration. - Run
hugo mod get github.com/pgsty/[email protected]. - Replace the old theme selection with the OINK
module.importsentry shown below; preserve unrelated imports and configuration. Merge the threemarkup.goldmarksettings andmarkup.highlight.noClasses: falsefrom the example. Do not replace your whole configuration with it. - Review site-owned
layouts/and assets, old theme shortcodes, and pagetype/layoutvalues: those overrides and conventions may still select the previous theme’s behavior. Keep content and make only the adaptations needed. - Run
hugo --panicOnWarning, then open an existing representative page withhugo server. Check its navigation, images, and code blocks before applying optional OINK features. Continue with verification.
From an empty directory to the first page
-
Create the skeleton and fetch the theme
What follows
hugo mod initis your own site’s module path, usually the repository address.hugo mod getwritesgo.modandgo.sum, and both are committed.Before building, create
.gitignoreso generated files stay out of Git. LeaveenableGitInfooff until you have made the first commit:.gitignoreThe newest version number is on GitHub Releases; the
v1.2.0on this page is what this site currently pins. A production site pins a release tag rather than followingmain:@latestis a one-off resolution, not a version policy. -
Writing
hugo.ymlFor this new site only, rename the generated
hugo.yamltohugo.yml(Hugo accepts both) and replace its contents with the following. Existing sites should merge the relevant settings instead:hugo.ymlWhat each of the five blocks governs:
Block Governs Consequence of omitting it Top level + languagesSite name, domain, languages and navbar menu A wrong baseURLsends every absolute link astray in productionmarkup.goldmarkThe three component prerequisites An attribute line becomes a literal {.steps}in the proseparamsSearch, repository links, shell switches Interactive features stay off; the theme does not decide for the site outputsThe per-page .md,llms.txtand print pagesNo “Copy as Markdown” in the page menu, and no print view moduleReferences the theme and declares the Hugo floor The build cannot find the theme Mathematics additionally needs Goldmark’s passthrough extension; see Math. Every key’s full meaning and default is in Configuration.
-
Write the first page
Every top-level directory under
content/is a section, and the directory structure is the sidebar structure. A documentation section needs at least an_index.md:content/docs/_index.mdcontent/docs/install.mdWrite explicit
{#id}anchors on headings: when a translation is added later, the two languages’ anchors have to correspond. How to write a page is in Writing pages. -
Preview
Open http://localhost:1313/docs/; the Docs section lists Install. The home page is still empty until you add home content. Edit the Install page and confirm that the preview updates.
Other install methods
The steps above use a Hugo Module. The other three address particular
constraints: network isolation, a platform that requires the build input to
contain the whole theme tree, or an organization that reviews its own copy of
the theme. Apart from hugo mod vendor, none of them creates a Go module, and
the site references the theme with theme: oink rather than module.imports.
The shared cost is that version resolution and integrity checking become your
responsibility.
Hugo Module (recommended)
The only method where Hugo resolves the version itself, verifies the checksum,
and leaves an audit record in go.sum. hugo mod graph shows what actually
resolved and hugo mod get -u upgrades. It needs Go on the machine.
Git submodule
Record an exact theme commit in the site repository:
CI must initialize the submodule before running Hugo, or themes/oink is an
empty directory:
Offline archive
For network-isolated environments. Two paths, both prepared on a connected machine and carried in whole.
With hugo mod vendor, the resolved theme source is frozen into the site
directory, and later builds need neither the network nor Go.
When _vendor/ exists Hugo prefers it (hugo mod graph prints +vendor), and
module.imports in hugo.yml stays as it is. This step needs Go; the builds
after it do not. Upgrading the theme means returning to a connected environment
and running hugo mod get and hugo mod vendor again.
_vendor/ collects only the directories the theme mounts (assets, data,
i18n, layouts, static) plus hugo.yaml and theme.toml. It does not
include LICENSE, NOTICE or VENDOR.json. To redistribute that archive, take
those three files from the theme repository as well.
With a tag source archive, no Go module is created; a version of the theme is
simply unpacked into themes/oink/.
The theme repository’s root is the module root, so unpacking lands directly on
layouts/, assets/, i18n/ and static/ with no further level to descend
into. Redistribution must keep LICENSE, NOTICE and VENDOR.json; the last
records each third-party runtime’s version, source, licence path and SHA-256,
and is what an offline audit rests on.
When moving between machines, generate the archive and its checksum from an immutable tag on the connected side:
Carry the archive and its .sha256 into the isolated environment, verify, then
unpack:
An archive produced this way is your own artifact, not a project release. Whether a given tag’s release page carries an archive and a checksum file varies by release; verify the checksum independently when using a public attachment.
Before building offline, confirm the archive is complete. All eleven of these must be present:
themes/oink/
oink/
- go.modmodule path declaration, used when resolving as a Hugo Module
- hugo.yamltheme default parameters and the Hugo version floor
- theme.tomltheme metadata, required by the theme: oink method
- LICENSEApache-2.0
- NOTICEupstream attribution; must be kept on redistribution
- VENDOR.jsonthird-party runtime manifest: version, source, licence path, SHA-256
- assets/SCSS, JS and the third-party runtimes shipped with the theme
- layouts/templates, partials, shortcodes, render hooks
- static/font files, published as is
- i18n/32 interface language files
- data/the SPDX licence table behind the page-end attribution line
Pinned source copy
When a hosting platform needs the theme files in the site repository, use the
tag archive procedure above and unpack it into
themes/oink/. Set theme: oink and commit the extracted files together with
the tag and checksum you verified.
A plain git clone ... themes/oink leaves a nested .git directory. Adding it
to the parent repository records a Git link, not the theme files; it therefore
does not provide this self-contained source copy. Use a submodule if you want
Git to track the theme by reference.
The four methods compared
| Method | Needs Go | Version auditable | Theme source in your repository | Use when |
|---|---|---|---|---|
| Hugo Module | Yes | go.sum verifies automatically |
No | The default |
| Git submodule | No | The repository records the commit | By reference | The theme source has to be in the repository |
| Offline archive | No | Checksums verified by hand | Yes | Network isolation |
| Pinned source copy | No | Record the tag and checksum | Yes | The platform requires a complete tree |
Bootstrap, Font Awesome, the fonts, and the search and diagram runtimes all
ship with the theme. A site needs no node_modules, no PostCSS, no RTLCSS and
no CDN. Tutorials that install npm dependencies for a Docsy site describe
upstream Docsy’s process and do not apply to OINK.
Developing against a local theme checkout
This section applies only when changing the theme and the site together. Clone the two repositories as siblings:
Use the HUGO_MODULE_REPLACEMENTS environment variable to substitute the local
checkout temporarily, leaving go.mod untouched:
The documentation site’s Makefile is an alias for exactly these commands, and
make dev and make check expect the theme checkout at the sibling ../oink:
A Go workspace (go work init plus HUGO_MODULE_WORKSPACE=go.work) is an
equivalent alternative. Both apply to the local machine only: CI and production
builds use the version in go.mod, and go.work is never committed.
Verify
It passes when the build ends with Total in … and no WARN or ERROR. Then
confirm:
/docs/opens and the sidebar holds the page you wrote- The navbar has a search box that finds the heading you just wrote
- The light/dark toggle is present, and code block colours follow it (which shows
markup.highlight.noClasses: falsetook effect) git status --shortlists only source changes; generated output is ignored. For the Module path, commit bothgo.modandgo.sum; other install methods keep their own theme source or submodule record.
Related
- Get started — choose between Starter, an existing Hugo site, and migration
- OINK Starter — the recommended new-site path
- Starter repository tour — what each template directory owns
- Configuration — every
hugo.ymlkey and its default - Writing pages — how to keep writing after the first page
- Upgrade — upgrading the theme module, and migrating from Docsy