Skip to content
Back to skills

Hugo

BSecurity

Hugo is a static site generator that turns Markdown content and templates into a complete HTML website in seconds, with no database or server runtime. Use when a user asks to create a Hugo site or blog, add a theme, write posts with front matter, preview with hugo server, configure hugo.toml, build the site for production, find unpublished drafts, or deploy a Hugo site to GitHub Pages or a cloud bucket.

  • 155 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 4, 2026
devopsjavascriptgojavabashazuregitapidatabasesecuritydocumentation

Works with

  • terminal
  • api

Security analysis

B88/100
  • criticalDownloads and executes remote scripts — classic supply chain attack

Pro scans all 2 files and shows the line behind each finding

Scanned October 4, 2026

npx -y skills add TerminalSkills/skills --skill hugo --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Hugo?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Hugo
[![Security: B — Skills Directory](https://www.skillsdirectory.com/api/skills/terminalskills-hugo/badge)](https://www.skillsdirectory.com/skills/terminalskills-hugo)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: hugo
description: >-
  Hugo is a static site generator that turns Markdown content and templates
  into a complete HTML website in seconds, with no database or server runtime.
  Use when a user asks to create a Hugo site or blog, add a theme, write posts
  with front matter, preview with hugo server, configure hugo.toml, build the
  site for production, find unpublished drafts, or deploy a Hugo site to
  GitHub Pages or a cloud bucket.
license: Apache-2.0
compatibility: "Hugo v0.158.0+ on macOS, Linux or Windows 10+; Git for themes and deployment; Go only for Hugo Modules or building from source"
metadata:
  author: terminal-skills
  version: "1.0.0"
  category: development
  tags: ["hugo", "static-site-generator", "markdown", "blog", "github-pages"]
  repository: https://github.com/gohugoio/hugo
---
# Hugo — Static sites from Markdown and templates

## Overview

Hugo is a single binary that reads a project directory (content, templates, assets, configuration) and writes a finished website to `public/`. It includes a development server with live reload, asset pipelines for CSS, JavaScript and images, multilingual support, and taxonomies such as tags and categories. Reach for it when the result is documentation, a blog, a landing page or a company site that can be served as plain files.

## Instructions

### Installation

```bash
brew install hugo                    # macOS and Linux
winget install Hugo.Hugo.Extended    # Windows
choco install hugo-extended          # Windows, alternative
scoop install hugo-extended          # Windows, alternative
hugo version
```

Linux distributions package it too (`snap install hugo`, `apt install hugo`, `dnf install hugo`, `pacman -S hugo`), but apart from the snap these repositories are often behind the current release. Check `hugo version` afterwards: this skill assumes v0.158.0 or later. Prebuilt archives for every platform are on https://github.com/gohugoio/hugo/releases/latest.

Hugo ships in four editions: standard, deploy, extended and extended/deploy. Standard is enough unless the site needs `hugo deploy` (deploy editions) or the deprecated LibSass transpiler (extended editions). Sass through Dart Sass works in every edition. Most package managers install an extended edition.

### Create a project

```bash
hugo new project saltmarsh-journal
cd saltmarsh-journal
git init
git submodule add https://github.com/gohugo-ananke/ananke themes/ananke
```

`hugo new site` is an alias for the same command and is what older tutorials show. Add `--format yaml` to get `hugo.yaml` instead of `hugo.toml`. The skeleton contains `archetypes/`, `assets/`, `content/`, `data/`, `i18n/`, `layouts/`, `static/` and `themes/`. Browse themes at https://themes.gohugo.io/, or scaffold one with `hugo new theme harbor`.

### Configure the site

```toml
baseURL = 'https://journal.saltmarshbakery.co/'
locale = 'en-gb'
title = 'Saltmarsh Bakery Journal'
theme = 'ananke'
enableRobotsTXT = true

[params]
  description = 'Recipes and notes from a small coastal bakery'

[[menus.main]]
  name = 'Recipes'
  pageRef = '/recipes'
  weight = 10

[permalinks.page]
  posts = '/:year/:month/:slug/'
```

This is `hugo.toml` in the project root. `baseURL` must start with the protocol and end with a slash. `locale` replaced `languageCode` in v0.158.0. Put custom values under `[params]`. Keep the file short: set only what differs from the defaults.

```bash
hugo config | grep -i baseurl    # show the effective configuration
```

### Write content

```bash
hugo new content content/posts/first-sourdough-loaf.md
```

Run it from the project root. The file is created from `archetypes/default.md` (or `archetypes/posts.md` when it exists) with `draft = true`. A finished post looks like this:

```toml
+++
date = '2026-09-14T08:30:00+01:00'
draft = true
title = 'First Sourdough Loaf'
tags = ['sourdough', 'starter']
+++
Feed the starter twice before mixing the dough.
```

Front matter delimited by `+++` is TOML, `---` is YAML. Reserved fields include `title`, `date`, `draft`, `publishDate`, `expiryDate`, `slug`, `weight`, `description` and `aliases`; custom fields go under `params`. A page is left out of the build when `draft` is true, `date` or `publishDate` is in the future, or `expiryDate` has passed.

### Preview locally

```bash
hugo server --buildDrafts --navigateToChanged
```

The server listens on http://localhost:1313/ (bound to 127.0.0.1), rebuilds on every change and reloads the browser. It runs until interrupted, so start it in the background or let the user run it. Useful flags: `--port 1414`, `--bind 0.0.0.0` to reach it from another device, `--disableFastRender` for full re-renders.

### Build for production

```bash
hugo build --gc --minify --cleanDestinationDir
```

Plain `hugo` runs the same build. Output goes to `public/`. Hugo overwrites files there but does not delete old ones; `--cleanDestinationDir` removes stale files from `public/`, which matters after unpublishing a page. Override settings per build with `--baseURL`, `--destination` and `--environment`.

### Review content status

```bash
hugo list drafts
hugo list future
hugo list expired
hugo list published
```

Each prints CSV with the columns `path,slug,title,date,expiryDate,publishDate,draft,permalink,kind,section`.

### Environments and environment variables

```bash
hugo build --environment staging
HUGO_BASEURL=https://staging.saltmarshbakery.co/ hugo build
```

The environment is `production` for `hugo build` and `development` for `hugo server`. Settings can be split into `config/_default/hugo.toml` plus overrides such as `config/staging/hugo.toml`. Any setting can come from a variable prefixed with `HUGO_`; site parameters use `HUGO_PARAMS_`. Variables win over the configuration file.

### Themes as Hugo Modules

```bash
hugo mod init github.com/saltmarsh-bakery/journal
hugo mod get -u
hugo mod tidy
```

Modules are an alternative to Git submodules and require Go on the machine. After `hugo mod init`, declare the import in `hugo.toml`:

```toml
[module]
  [[module.imports]]
    path = 'github.com/gohugo-ananke/ananke/v2'
```

The path must match the `module` line in the theme's own `go.mod`, including a version suffix such as `/v2`.

### Deploy

Any host that serves static files can publish `public/`. For GitHub Pages, set the repository's Pages source to "GitHub Actions" and build in a workflow:

```yaml
name: Build and deploy
on:
  push:
    branches: [main]
permissions:
  contents: read
  pages: write
  id-token: write
env:
  HUGO_VERSION: 0.167.0
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
        with:
          submodules: recursive
          fetch-depth: 0
      - id: pages
        uses: actions/configure-pages@v6
      - name: Install Hugo
        working-directory: ${{ runner.temp }}
        run: |
          base="https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}"
          curl -sfLO "${base}/hugo_${HUGO_VERSION}_linux-amd64.tar.gz"
          curl -sfLO "${base}/hugo_${HUGO_VERSION}_checksums.txt"
          grep "hugo_${HUGO_VERSION}_linux-amd64.tar.gz" "hugo_${HUGO_VERSION}_checksums.txt" | sha256sum -c -
          mkdir -p "${HOME}/.local/hugo"
          tar -C "${HOME}/.local/hugo" -xf "hugo_${HUGO_VERSION}_linux-amd64.tar.gz"
          echo "${HOME}/.local/hugo" >> "${GITHUB_PATH}"
      - run: hugo build --gc --minify --baseURL "${{ steps.pages.outputs.base_url }}/"
      - uses: actions/upload-pages-artifact@v5
        with:
          path: ./public
  deploy:
    needs: build
    runs-on: ubuntu-latest
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    steps:
      - id: deployment
        uses: actions/deploy-pages@v5
```

With a deploy edition, `hugo deploy --target production --dryRun` previews a sync of `public/` to the Amazon S3, Google Cloud Storage or Azure Blob target defined under `[deployment]`; drop `--dryRun` to apply it.

## Examples

### Example 1: Start a blog with a theme and a first post

**Request:** "Set up a Hugo blog for my bakery called Saltmarsh Bakery Journal, with the Ananke theme and a first post about sourdough."

```bash
hugo new project saltmarsh-journal
cd saltmarsh-journal
git init
git submodule add https://github.com/gohugo-ananke/ananke themes/ananke
hugo new content content/posts/first-sourdough-loaf.md
hugo build --gc --minify
```

Between the last two commands the agent writes the `hugo.toml` shown above, fills in the post body and sets `draft = false`.

**Result:** the build ends with a summary table and `public/` holds the site:

```text
                  │ EN
──────────────────┼────
 Pages            │ 16
 Paginator pages  │  0
 Non-page files   │  0
 Static files     │  1
 Processed images │  0
 Aliases          │  3
 Cleaned          │  0

Total in 30 ms
```

The post is written to `public/2026/09/first-sourdough-loaf/index.html`, next to `index.html`, `index.xml` (RSS), `sitemap.xml`, `robots.txt` and `tags/sourdough/index.html`.

### Example 2: Find out why a post is missing from the live site

**Request:** "I wrote the rye starter post last week but it is not on the site. What is wrong?"

```bash
hugo list drafts
hugo list future
```

**Result:**

```text
path,slug,title,date,expiryDate,publishDate,draft,permalink,kind,section
content/posts/rye-starter-day-5.md,,Rye Starter Day 5,2026-09-22T07:15:00+01:00,0001-01-01T00:00:00Z,2026-09-22T07:15:00+01:00,true,https://journal.saltmarshbakery.co/2026/09/rye-starter-day-5/,page,posts
```

The post is still marked `draft = true`. The agent changes that line to `draft = false` in `content/posts/rye-starter-day-5.md`, runs `hugo build --gc --minify --cleanDestinationDir`, and confirms that `public/2026/09/rye-starter-day-5/index.html` exists.

## Guidelines

- **Check the version first.** Tutorials and distribution packages lag behind. On releases before v0.158.0 the language setting is `languageCode`, not `locale`.
- **Do not commit `public/` or `resources/`.** Hugo recreates them on every build. Add both to `.gitignore` and let CI build the site.
- **Stale files are a real risk.** Without `--cleanDestinationDir`, a page that became a draft again stays in `public/` and gets deployed. Note that the flag deletes anything in `public/` the build did not produce.
- **Never deploy a `-D` build.** `--buildDrafts`, `--buildFuture` and `--buildExpired` are for previews. Setting them in the configuration file publishes unfinished content for everyone on the team.
- **`baseURL` decides every absolute link.** A wrong value breaks CSS and navigation on the host. On GitHub Pages project sites the path includes the repository name; pass it with `--baseURL` in CI.
- **Themes as submodules need `submodules: recursive`** in the checkout step, otherwise CI builds an empty site without an error.
- **The development server is not a production web server.** It has limited options; publish the files from `public/` instead.
- **Third-party themes and modules run templates inside your build.** Review a theme before adding it, pin it to a commit or version, and leave the `_merge` setting at its default so a theme cannot change `security` or `markup` configuration.
- **`hugo deploy` deletes remote files that are missing locally** (up to 256 per run by default). Always start with `--dryRun`, and only run the real sync when the user has confirmed the target.
- **Hugo does not follow symbolic links.** Use module mounts to bring in content from another directory.
- **When not to use Hugo:** pages that need per-request server logic, logged-in user content or a database. Hugo produces files at build time; pair it with a separate API or choose an application framework.

Files in this skill

  • SKILL.md11.5 KB
  • _scores.json1.6 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…