Hugo Documentation Automation Patterns

hugo automation documentation static-site svelte5

Overview

Hugo v0.140+ introduced significant changes to template handling, JSON output, and theme architecture. This page documents proven patterns for automating documentation workflows with Hugo as the core engine, including Svelte 5 integration strategies.

Key Patterns

1. JSON Feed as API

Hugo’s custom output formats let you generate index.json for any section, turning your static site into a headless CMS:

1
2
3
4
5
6
7
[outputFormats.JSON]
  mediaType = "application/json"
  baseName = "index"
  isPlainText = true

[outputs]
  section = ["HTML", "RSS", "JSON"]

Template (layouts/_default/list.json.json):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{{- $items := slice -}}
{{- range .Pages -}}
  {{- $items = $items | append (dict
       "title" .Title
       "url" .RelPermalink
       "summary" (.Summary | truncate 160)
       "date" (.Date.Format "2006-01-02")
       "tags" .Params.tags) -}}
{{- end -}}
{{- $items | jsonify -}}

Critical: Use .RelPermalink not .Permalink โ€” absolute URLs break when the domain differs between build and serve environments.

2. Zero-Build Dashboard Integration

Instead of a separate Svelte/Vite build, place a vanilla JS SPA at static/dashboard/index.html. Hugo copies static/ โ†’ public/ verbatim. The dashboard fetches /topics/index.json and renders cards client-side.

Benefits:

  • No Node.js dependency in deploy pipeline
  • Single hugo --minify build step
  • Nginx serves everything statically

3. Svelte 5 + Hugo Hybrid Architecture

For interactive components, embed Svelte 5 as hydrated islands within Hugo pages:

1
2
3
4
5
content/
  posts/
    my-post.md          # Hugo markdown
  components/
    Counter.svelte      # Svelte 5 component

Build pipeline:

1
2
3
4
5
6
7
# 1. Build Svelte components to IIFE modules
vite build --mode ssg

# 2. Hugo builds markdown + copies Svelte assets
hugo --minify

# 3. Nginx serves both

Hugo shortcode for Svelte islands:

1
2
3
4
5
6
<!-- layouts/shortcodes/svelte.html -->
<div id="svelte-{{ .Get 0 }}" data-props='{{ .Inner | jsonify }}'></div>
<script type="module">
  import './components/{{ .Get 0 }}.js';
  hydrate(App, { target: document.getElementById('svelte-{{ .Get 0 }}'), props: JSON.parse(document.getElementById('svelte-{{ .Get 0 }}').dataset.props) });
</script>

Usage in markdown (shortcode):

1
2
3
{{% svelte "Counter" %}}
{"initial": 5}
{{% /svelte %}}

4. Content Taxonomy vs Section

Gotcha: Declaring topic = "topics" in [taxonomies] makes content/topics/ a taxonomy, not a section. Section-level index.json won’t generate.

1
2
3
4
5
6
7
8
# CORRECT โ€” tags only, topics is a section
[taxonomies]
  tag = "tags"

# WRONG โ€” breaks section JSON output
[taxonomies]
  tag = "tags"
  topic = "topics"

5. Front Matter Tag Arrays

Tags must be proper YAML arrays. Comma-separated strings become a single tag:

1
2
3
4
5
# CORRECT
tags: ["hugo", "automation", "docs", "svelte5"]

# WRONG โ€” becomes one tag "hugo, automation, docs, svelte5"
tags: ["hugo, automation, docs, svelte5"]

6. Hugo 0.140 Template Changes

  • $.IsMenu and $currentPage.IsMenu removed โ€” use simple nav loops without active-state detection
  • .Site.RegularPages in section templates shows ALL pages โ€” use .Pages for section-scoped listing
  • JSON templates with .json.json extension are flagged by linters as invalid JSON โ€” this is a false positive; these are Hugo templates

Svelte 5 Integration Patterns

Pattern A: Vanilla JS Dashboard (Zero Build)

  • Current LLM-Wiki approach
  • No Svelte dependency in production
  • Best for: read-only dashboards, search, filtering

Pattern B: Svelte 5 Islands (Partial Hydration)

  • Hugo renders static content
  • Svelte 5 hydrates interactive widgets
  • Best for: calculators, forms, real-time widgets

Pattern C: SvelteKit + Hugo Hybrid

  • SvelteKit for app routes
  • Hugo for content routes
  • Shared component library
  • Best for: full apps with documentation

Automation Pipeline

1
research-automation.py โ†’ content/topics/*.md โ†’ hugo build โ†’ public/topics/index.json โ†’ dashboard
  1. Research script generates/updates markdown with proper front matter
  2. Hugo builds HTML + JSON output
  3. Dashboard fetches JSON, renders searchable card grid
  4. Deploy: hugo --minify && sudo nginx -t && sudo systemctl reload nginx

Svelte 5 Component Structure for Hugo

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
hugo-llm-wiki/
โ”œโ”€โ”€ static/
โ”‚   โ””โ”€โ”€ components/           # Built Svelte 5 components (IIFE)
โ”‚       โ”œโ”€โ”€ Counter.js
โ”‚       โ””โ”€โ”€ SearchWidget.js
โ”œโ”€โ”€ components/               # Source Svelte 5 components
โ”‚   โ”œโ”€โ”€ Counter.svelte
โ”‚   โ””โ”€โ”€ SearchWidget.svelte
โ”œโ”€โ”€ vite.config.ssg.ts        # Vite config for SSG build
โ””โ”€โ”€ layouts/shortcodes/
    โ””โ”€โ”€ svelte.html           # Hugo shortcode

vite.config.ssg.ts:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import { defineConfig } from 'vite';
import { svelte } from '@sveltejs/vite-plugin-svelte';

export default defineConfig({
  plugins: [svelte({ compilerOptions: { runes: true } })],
  build: {
    lib: {
      entry: 'components/index.ts',
      formats: ['iife'],
      name: 'SvelteComponents'
    },
    outDir: '../static/components'
  }
});

Evolution Notes

Content last updated: 2026-06-05 Next review: 2026-06-12