Home / Alt manpages / hugo-mod-vendor(1)

  • hugo-mod-vendor(1)
  • User command
  • linux

Make Hugo Module Builds Reproducible with hugo mod vendor

Hugo's module system can fetch dependencies from its cache while it builds. hugo mod vendor copies those dependencies into a project-local _vendor directory, so the project has a visible, reviewable copy to build from. This guide uses the Hugo 0.123.7 command installed on this machine.

Allow about 10 minutes for a small site, longer if dependencies must be downloaded. You need a Hugo module project, write access to its directory, and a clean enough working tree to review generated files. You do not normally need root privileges. Do not use sudo for a project in your home directory: it can leave the new files owned by root.

Checkpoint: confirm the project and command

Run these checks from the directory containing the site's go.mod file. If the file is elsewhere, change to the module root first.

$ pwd
$ test -f go.mod && echo "module root: yes"
$ hugo version
hugo v0.123.7+extended linux/amd64 BuildDate=2026-03-17T19:51:14Z VendorInfo=ubuntu:0.123.7-1ubuntu0.3+esm2

The command is a subcommand of Hugo, not a separate executable. Check its locally installed options before copying a command from a different Hugo release:

$ hugo mod vendor --help
Vendor all module dependencies into the _vendor directory.

The installed interface accepts --baseURL, --cacheDir, --contentDir and --theme, plus the inherited configuration and source options. The current upstream documentation may list additional options in newer releases, so treat this machine's help output as the contract for this installation.

1. Inspect what Hugo thinks the project imports

Before changing the tree, inspect the module graph. This separates a missing dependency from a vendoring problem and gives you a record to compare afterwards.

$ hugo mod graph
$ git status --short

The graph is a set of module relationships. An empty graph can be correct for a module with no imported dependencies. If the command reports a malformed module file, an unavailable version, or a replacement path that does not exist, fix that project configuration first. Vendoring cannot repair an invalid dependency graph.

2. Record the starting state

Vendoring writes files, so capture the starting state before you run it. This also makes it easier to tell generated changes from work already in progress.

$ git status --short
$ test ! -e _vendor || find _vendor -maxdepth 2 -type f -print | sort | head -40

If _vendor already contains hand-edited files, stop and preserve them before continuing. Hugo's documentation recommends overriding vendored content from the project root rather than editing the copy in _vendor. A normal source-control commit is the safest record; a separate copy outside the project is useful when you cannot commit yet.

3. Vendor the dependencies

Run the command from the module tree. The ordinary form needs no flags:

$ hugo mod vendor

A successful run may produce no terminal output. That is not a failure. The useful result is the _vendor directory and its copied module files. Confirm both the directory and the source-control change:

$ test -d _vendor && echo "vendor directory: present"
$ find _vendor -maxdepth 3 -type f -print | sort | sed -n '1,40p'
$ git status --short

Do not assume that every directory under themes will appear in _vendor. Hugo's module documentation says modules inside the themes directory are not vendored. Check the graph and the project mounts when a theme is missing, rather than copying files into an invented path.

4. Build using the vendored tree

Run the same build command used by your project and inspect the result. Hugo looks in _vendor for dependencies when a module is vendored.

$ hugo --destination /tmp/example-hugo-public
$ test -f /tmp/example-hugo-public/index.html && echo "build: present"

The destination above is a disposable example path. Replace it with your real build destination in a deployment script. The --destination option is inherited by hugo mod vendor, but it controls where Hugo writes rendered output; it is not a switch for the _vendor location. Keep those two concerns separate.

5. Use the relevant option only when needed

Most projects should use the default command. If a project has a non-default configuration location, pass the inherited configuration option explicitly:

$ hugo mod vendor --config /path/to/site/config.yaml

If several configured themes need to be selected for the operation, the command also exposes the repeatable --theme option. Use the theme names as they exist below the configured themes directory:

$ hugo mod vendor --theme example-theme

These paths and names are placeholders. Do not paste them unchanged. An incorrect configuration or theme name can make a valid module appear to be missing.

Recovery and safe removal

Vendoring is reversible only if you have not made unique edits inside _vendor. Review the diff before deleting anything:

$ git diff --stat
$ git diff -- _vendor go.mod go.sum

If the generated directory is wrong, restore it from your normal source-control operation or move it aside after checking for local edits. Once it is removed, rerun hugo mod vendor to recreate it. Never remove a shared or system directory, and do not run a broad recursive deletion from an uncertain working directory.

Done means

  • hugo version identifies the installed release and hugo mod vendor --help matches the command you used.
  • The module graph resolves without errors.
  • _vendor exists and contains the expected dependency files.
  • A normal Hugo build succeeds while using the vendored dependencies.
  • The source-control diff contains only changes you understand and intend to keep.