Hugo Input Formats, Directory Layout, and Workflow
The Hugo static site generator takes some plain-text content, marries it to a bunch of HTML templates, and produces a set of complete, static HTML pages that can be served by any generic, stand-alone web server. It allows for a variety of input formats, and expects a particular layout of its workspace.
Part 2: Input Formats, Directory Layout, Tooling and Workflow
In its most basic mode of operation, Hugo expects a hierarchy of input files
in a source directory (by default called
content/). When run, Hugo
marries these to the appropriate templates and places the generated
HTML files in an output directory (by default:
public/). The content
of this directory can be placed, as is, in the docroot of a public-facing
web server. If Hugo encounters other files (such as images or stylesheets)
in the source directory, it copies them unmodified to the output directory.
Input format for “content” is usually Markdown. Out of the box, Hugo
can also handle plain HTML and Emacs Org-Mode. AsciiDoc, reStructuredText,
and Pandoc require the appropriate tools to be installed. Hugo determines
the format by the file extension (
.org) or from the
frontmatter or preamble of each file.
Hugo input files typically begin with a preamble in YAML format. (TOML and JSON are also possible.) The preamble can be used to set configuration values for each piece of content: for example, it is possible to assign keyword tags to the page, to modify its public URL, or to specify the specific template to render it.
Here is an example (in YAML format):
--- title: "A Hugo Survival Guide" date: "2020-02-22T22:22:22-00:00" slug: "a-hugo-survival-guide" ---
Notice the YAML-specific fencing with
---. (TOML uses
+++, and for
JSON, the entire preamble needs to be enclosed in curlies
Input File Warnings and Remarks
Frontmatter parameters can interfere with rendering in surreptitious
ways. For example, by default, Hugo creates new content items with a
draft set to
true, with the consequence that
no output will be generated for this piece of content.
Markdown must be HTML-compatible. For example, it is not possible
to have emphasis (
_ ... _) span multiple paragraphs. If you want to
emphasize two consecutive paragraphs, emphasize them individually.
Markdown is less expressive than HTML. In particular, Markdown has no provisions to include rich formatting directives (such as color specifications or font changes) in a Markdown file. Embedded HTML or shortcodes provide workarounds. (Shortcodes are pre-defined snippets of Go Template language that can be embedded in a Markdown file and will be evaluated when the content is rendered.) Note that by default, recent versions of Hugo do not pass through embedded HTML, but discard it. (See next paragraph.)
HTML files without frontmatter, in general, will be copied to the output as-is, whereas HTML files with frontmatter (even if it is empty) will be treated as content files and subject to template expansion.
Usually, HTML that is embedded in Markdown is passed through untouched.
Recent versions of Hugo do not behave like this by default; instead,
the following addition must be made to the global configuration file
config.toml to enable this behavior:
[markup] [markup.goldmark] [markup.goldmark.renderer] unsafe = true
Input processors are often external tools or libraries that Hugo uses to parse and process input files; some may behave slightly different than others. The Hugo documentation may not always be up-to-date in this regard.
Important Frontmatter Parameters
Hugo defines a large number of parameters that can be set via the frontmatter; themes may define additional ones. In general, these parameters are optional: they are a low-level way to override global configurations (either default or from the global configuration file) for a specific piece of content. Two remarks:
There is no magic here. All that the “frontmatter” does is to populate or override some of Hugo’s internal key/value data structures.
Frontmatter is nice because it often gives fairly detailed control over individual pieces of content. At the same time, it scatters configuration information widely. I have found it better to rely as much as possible on global configurations and only override them, where necessary, for individual pieces of content.
Some of the more important pre-defined parameters include the following:
- The primary “date” associated with this page. Other date-related frontmatter
lastmod. (If present, Hugo will use the first two to decide whether to publish this piece of content or not.)
- May be used by the template to populate
<meta>tags in the HTML header. (Not all themes use this information.)
- Keyword tags assigned to this piece of content. Hugo uses this information to create lists of all tagged pages. (Also see the discussion of “Taxonomies”.)
Naming and URL Management
- This is typically used by the template to populate the page’s headline and to set the page’s title in the HTML header. It may be required by some themes for the site to work properly
- Specify the slug (that is, the last part of the URL); if not present, the slug will be generated from the file name.
- Complete path, relative to the document root, for this piece of content. Intermediate directories will be created as necessary.
- One or more paths, relative to the document root. For each one, Hugo will create a file with a redirect notice that redirects to the current piece of content. (Note the spelling of the keyword!)
- Do not publish, unless the
--buildDraftsoption is given. (Hugo sets this parameter to
trueby default. It is absolutely safe to remove this parameter from the frontmatter of any piece of content.)
- The template to be used to render this document. (The details of the template lookup are complicated, see the Hugo documentation.)
- A numeric value that is used when sorting pages (in list views, for instance). May be positive or negative, integer or floating point.
- Specify the markup format of the current document.
Hugo assumes a specific layout of its working directory. You can use Hugo itself to create a skeleton workspace directory for a new project. Run:
hugo new site demo
This will create a new directory called
demo. In this directory,
you will find the following files and directories:
All of them are empty or almost empty by default.
All content, in plain text (Markdown), goes into the
this is the source or input directory. Notice that while frontmatter is
typically YAML, the global config file is usually TOML.
archetype/ directory holds skeleton outlines for content documents;
essentially some default frontmatter. They are used by the
command to create new content files. Archetypes may contain references
to Hugo variables; if so, they are be evaluated by
hugo new. The
frontmatter in the resulting starter files will contain only values, not
references to Hugo variables.
Complete, downloaded themes go into the
themes/ directory. It is
possible to provide customized templates that may override some of
the theme’s settings; they go into the
static/ directory is a repository for static files that are
libraries. It is possible to create subdirectories (such as
they will be replicated into the output directory. The
finally, is intended as a place for additional configuration data, or for
static data to populate a page.
Hugo recognizes additional directories. For example, if one wants to
let Hugo process a stylesheet, then it needs to be placed into an
assets/ directory. These directories are not created by default;
see the Hugo documentation for additional details.
Finally, many of these directories can be changed using command-line flags. Keep in mind, however, that Hugo will generally only access files that are below the current working directory; it will not follow arbitrary paths.
The workflow description below assumes that you already have Hugo installed. As a Go program, Hugo is a stand-alone application that does not depend on external libraries. There are two different versions of Hugo in a release. The “extended” version includes some additional functionality for image processing (scaling and cropping), for the compilation of SASS/SCSS files, and some other features. Be aware that some themes require the extended version!
In general, the
hugo command must be executed within the the project’s
workspace directory. The
hugo command takes a number of subcommands and
command-line options. Some of the most important subcommands are:
- When invoked without a subcommand, Hugo will process the inputs and
static files, creating a set of static HTML pages and auxiliary files.
By default, Hugo will create a directory
public/inside the project’s workspace as destination for the output files. Hugo also creates a
resources/directory as destination for intermediate results (such as cropped images).
- When invoked with the
servercommand, Hugo does not write its results out to disk. Instead, it starts up an HTTP server (by default on port 1313) and serves the generated pages from memory. The server watches the content directory and configuration file, and automatically refreshes the results when it detects changes. (This is primarily intended as a development tool.)
newcommand, when followed by a path in the
content/directory, will create a new file (as well as any required intermediate directories) at the given location. The file will be empty, except for the frontmatter, which will have been pulled from the
archtetypes/directory. Any Hugo variables within the frontmatter will have been evaluated.
hugo new site
- This, when followed by the desired directory name, will create a new workspace directory of the given name, and containing the default workspace directory hierarchy.
Compared to other build systems, Hugo’s tooling is fairly rudimentary. Many activities (such as adding a theme) require multiple, manual steps.
There is no
clean command or target. If there already is a
output directory, Hugo will continue placing results into it. It will
be necessary to manually remove
resources/) to get a
Diagnostics are extremely poor. If something doesn’t work, it is
very difficult to get any information what might be causing the
problem. (At the same time, the
hugo command does not follow the
Unix tradition to “succeed silently, but fail loudly”: it will chattily
and unnecessarily tell you when it has created a new file using
hugo new, but it will silently discard various input files according
to its own processing rules, leaving you none the wiser.)
hugo command (in particular the server) can get easily
confused or even crash when dealing with malformed input files, or the
temporary files that editors sometimes leave in working directories.
Here are the steps to create a project, add a theme, and begin creating content. Remember that, out of the box, Hugo does not contain a default theme: hence, not only is it necessary to add a theme, but also to configure it.
Note that this sequence of steps contains additional steps, compared to the version in the Hugo documentation!
Create a workspace and skeleton directory hierarchy using
hugo new site
Add a theme into the
themesdirectory in the workspace. This can be done using
gitor by downloading a theme and copying it to its destination; it is not done using a
A theme typically contains an
exampleSitedirectory, containing a complete website demonstrating the theme. Use its global configuration file (typically:
exampleSite/config.toml) as basis for the configuration file of your new project. Edit your copy of this file as needed. (The reason is that many themes require specific configurations values to work properly; using the configurations from the example site as basis provides a fairly reliable starting point.)
Possibly copy the contents of the theme’s
archetypes/directory into the corresponding top level location. (Again, the reason is that some themes require specific frontmatter variables that the default archetypes will not know about.)
Create some pieces of content using
hugo new. Edit them as desired. (Remember to remove any
draft: truelines from the frontmatter, otherwise Hugo will ignore the piece of content.) Alternatively, copy the files from the example site into your
content/directory to have a starting point.
Start the development server using
hugo server. (Default port 1313, use the
-pflag to change the port.)
Examine the site at
Finally, build the site using
hugo. Deploy the contents of the
public/output directory to the hosting provider of your choice. Remember that Hugo does not clean an existing output directory automatically if there is one.