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:

[outputFormats.JSON]
  mediaType = "application/json"
  baseName = "index"
  isPlainText = true
 
[outputs]
  section = ["HTML", "RSS", "JSON"]

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

{{- $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:

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

Build pipeline:

# 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:

<!-- 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):

{{%/* 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.

# 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:

# 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

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

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:

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