<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Hugo on kenji.blog</title><link>http://kenji.blog/en/categories/hugo/</link><description>Recent content in Hugo on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>en</language><copyright>kenjinote</copyright><lastBuildDate>Sun, 13 Sep 2026 03:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/en/categories/hugo/index.xml" rel="self" type="application/rss+xml"/><item><title>Hugo Theme Customization: How to Introduce Tailwind CSS</title><link>http://kenji.blog/en/p/hugo-tailwind-css-customization-guide/</link><pubDate>Sun, 13 Sep 2026 03:00:00 +0900</pubDate><guid>http://kenji.blog/en/p/hugo-tailwind-css-customization-guide/</guid><description>&lt;img src="http://kenji.blog/p/hugo-tailwind-css-customization-guide/img/eyecatch.jpg" alt="Featured image of post Hugo Theme Customization: How to Introduce Tailwind CSS" />&lt;h1 id="introduction-the-powerful-synergy-of-the-static-site-generator-hugo-and-tailwind-css">Introduction: The Powerful Synergy of the Static Site Generator Hugo and Tailwind CSS
&lt;/h1>&lt;p>In modern web frontend development, balancing performance and Developer Experience (DX) is one of the most critical challenges in every project. Combining &lt;strong>Hugo&lt;/strong>, which boasts some of the world&amp;rsquo;s fastest build speeds among static site generators (SSGs), with &lt;strong>Tailwind CSS&lt;/strong>, which introduced the innovative paradigm of utility-first CSS, can be considered an ultimate answer to this challenge.&lt;/p>
&lt;p>Hugo is written in Go and has the astonishing performance to finish building thousands of pages in just a few seconds or even milliseconds. On the other hand, Tailwind CSS accelerates design iterations and eliminates the context switching of jumping back and forth between CSS and HTML files by allowing you to write countless predefined utility classes (such as &lt;code>flex&lt;/code>, &lt;code>text-center&lt;/code>, &lt;code>mt-4&lt;/code>) directly into HTML.&lt;/p>
&lt;p>In this article, we will thoroughly and comprehensively explain the steps to introduce Tailwind CSS into a Hugo theme and further build an advanced asset pipeline (Hugo Pipes) using PostCSS, covering everything from the foundation of the architecture to mathematical performance optimization perspectives.&lt;/p>
&lt;hr>
&lt;h2 id="1-the-transition-of-utility-first-css-and-component-oriented-design">1. The Transition of Utility-First CSS and Component-Oriented Design
&lt;/h2>&lt;p>Before diving into the Tailwind CSS installation steps, it is highly beneficial to deeply understand the history and evolution of the CSS design philosophy behind why we should use Tailwind CSS.&lt;/p>
&lt;h3 id="the-limitations-of-traditional-css-design-bem-and-oocss">The Limitations of Traditional CSS Design (BEM and OOCSS)
&lt;/h3>&lt;p>In past web development, giving semantic class names was considered a best practice. For example, when creating a card component, HTML and CSS were separated as follows:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">div&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;card&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">img&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;card__image&amp;#34;&lt;/span> &lt;span class="na">src&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;image.jpg&amp;#34;&lt;/span> &lt;span class="na">alt&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;thumbnail&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">div&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;card__content&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">h2&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;card__title&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Title&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">h2&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">p&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;card__description&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Description goes here.&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">p&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">div&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">div&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-css" data-lang="css">&lt;span class="line">&lt;span class="cl">&lt;span class="p">.&lt;/span>&lt;span class="nc">card&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">border-radius&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">8&lt;/span>&lt;span class="kt">px&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">box-shadow&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">0&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="kt">px&lt;/span> &lt;span class="mi">6&lt;/span>&lt;span class="kt">px&lt;/span> &lt;span class="nb">rgba&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="mf">0.1&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">background-color&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mh">#ffffff&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">overflow&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">hidden&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">.&lt;/span>&lt;span class="nc">card__title&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">font-size&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mf">1.5&lt;/span>&lt;span class="kt">rem&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">font-weight&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">bold&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">color&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mh">#333333&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">/* Detailed styles continue below */&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>While such BEM (Block Element Modifier) based design works when the project scale is small, it tends to cause the following problems:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Naming exhaustion and fatigue&lt;/strong>: You have to think of new class names every time you create a similar component (e.g., &lt;code>card-news&lt;/code>, &lt;code>card-featured&lt;/code>).&lt;/li>
&lt;li>&lt;strong>CSS Bloat&lt;/strong>: The number of CSS lines continues to increase every time a new feature is added, and once written, CSS is rarely deleted out of fear that &amp;ldquo;we don&amp;rsquo;t know where it&amp;rsquo;s used,&amp;rdquo; leading to an accumulation of dead code.&lt;/li>
&lt;li>&lt;strong>Context Switching&lt;/strong>: Because HTML structure and CSS styles are managed in separate files, the number of times you switch tabs in your editor increases exponentially.&lt;/li>
&lt;/ol>
&lt;h3 id="paradigm-shift-by-tailwind-css">Paradigm Shift by Tailwind CSS
&lt;/h3>&lt;p>Tailwind CSS solves these problems with the approach of &amp;ldquo;combining utility classes.&amp;rdquo; Using Tailwind CSS, the above card component looks like this:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">div&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;rounded-lg shadow-md bg-white overflow-hidden&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">img&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;w-full h-48 object-cover&amp;#34;&lt;/span> &lt;span class="na">src&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;image.jpg&amp;#34;&lt;/span> &lt;span class="na">alt&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;thumbnail&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">div&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;p-6&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">h2&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;text-2xl font-bold text-gray-800&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Title&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">h2&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">p&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;mt-2 text-gray-600&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Description goes here.&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">p&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">div&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">div&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Since the class names themselves represent the specific values of styles (e.g., &lt;code>p-6&lt;/code> is &lt;code>padding: 1.5rem;&lt;/code>), you can predict the final rendering result just by looking at the HTML. Furthermore, Tailwind&amp;rsquo;s JIT (Just-In-Time) compiler extracts only the actually used classes into the production CSS file, reducing the CSS file size to the absolute minimum.&lt;/p>
&lt;hr>
&lt;h2 id="2-hugo-pipes-and-postcss-architecture">2. Hugo Pipes and PostCSS Architecture
&lt;/h2>&lt;p>To integrate Tailwind CSS into Hugo, you need to understand the asset processing pipeline called &lt;strong>Hugo Pipes&lt;/strong>. Hugo Pipes is a powerful feature that completes all asset-related processing internally within Hugo, such as compiling Sass/SCSS, bundling and minifying JavaScript, and executing the &lt;strong>PostCSS&lt;/strong> we will use this time.&lt;/p>
&lt;p>PostCSS is a tool for transforming CSS using JavaScript plugins. Tailwind CSS itself actually operates as a PostCSS plugin.&lt;/p>
&lt;h3 id="ast-abstract-syntax-tree-transformation-mechanism-by-postcss">AST (Abstract Syntax Tree) Transformation Mechanism by PostCSS
&lt;/h3>&lt;p>Understanding how PostCSS processes CSS is highly useful for troubleshooting. The following Mermaid diagram shows the pipeline of how PostCSS reads a CSS file, transforms it through plugins, and outputs the final CSS.&lt;/p>
&lt;pre class="mermaid">
flowchart TD
A[&amp;#34;Raw CSS (styles.css)&amp;#34;] --&amp;gt;|Parser| B[&amp;#34;AST (Abstract Syntax Tree)&amp;#34;]
B --&amp;gt; C[&amp;#34;Plugin 1: Tailwind CSS&amp;#34;]
C --&amp;gt; D[&amp;#34;Plugin 2: Autoprefixer&amp;#34;]
D --&amp;gt; E[&amp;#34;Plugin N: cssnano&amp;#34;]
E --&amp;gt;|Stringifier| F[&amp;#34;Compiled &amp;amp; Optimized CSS&amp;#34;]
&lt;/pre>
&lt;ol>
&lt;li>&lt;strong>Parser&lt;/strong>: Analyzes the inputted raw CSS string and converts it into an AST (Abstract Syntax Tree), a data structure that can be manipulated programmatically.&lt;/li>
&lt;li>&lt;strong>Plugins&lt;/strong>:
&lt;ul>
&lt;li>&lt;strong>Tailwind CSS&lt;/strong>: Scans template files (HTML or Markdown) and adds the used utility classes as nodes to the AST. It also expands the &lt;code>@tailwind&lt;/code> directive.&lt;/li>
&lt;li>&lt;strong>Autoprefixer&lt;/strong>: References the &lt;code>Can I Use&lt;/code> database and adds vendor prefixes (such as &lt;code>-webkit-&lt;/code>, &lt;code>-moz-&lt;/code>) to the AST properties as needed.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Stringifier&lt;/strong>: Converts the transformed AST back into a browser-readable CSS string and outputs it.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="3-environment-setup-and-prerequisites">3. Environment Setup and Prerequisites
&lt;/h2>&lt;p>Now, let&amp;rsquo;s move on to the actual installation steps. First, we will check if the necessary software is installed.&lt;/p>
&lt;h3 id="prerequisites">Prerequisites
&lt;/h3>&lt;ol>
&lt;li>
&lt;p>&lt;strong>Hugo Extended Version&lt;/strong>:
You must have the &lt;strong>Extended version&lt;/strong>, not the regular Hugo, as it includes Sass/SCSS processing capabilities and native PostCSS integration features. Run the following command in your terminal and verify that the version information contains the string &lt;code>extended&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">hugo version
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Expected output example:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># hugo v0.121.2-4146... windows/amd64 BuildDate=... VendorInfo=gohugoio +extended&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;/li>
&lt;li>
&lt;p>&lt;strong>Node.js and npm&lt;/strong>:
Dependencies like Tailwind CSS and PostCSS run on Node.js. Make sure Node.js (LTS version recommended) is installed.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">node -v
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">npm -v
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;/li>
&lt;/ol>
&lt;h3 id="installing-npm-packages">Installing npm Packages
&lt;/h3>&lt;p>Initialize npm in the project&amp;rsquo;s root directory (where Hugo&amp;rsquo;s configuration file &lt;code>hugo.toml&lt;/code> is located) and install the required packages.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Generate package.json&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">npm init -y
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Install Tailwind CSS, PostCSS, and Autoprefixer as development dependencies&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">npm install -D tailwindcss postcss postcss-cli autoprefixer
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;blockquote>
&lt;p>[!IMPORTANT]
If &lt;code>postcss-cli&lt;/code> is not installed, errors may occur when invoking PostCSS from inside Hugo. Because Hugo Pipes internally uses &lt;code>postcss-cli&lt;/code>, be absolutely sure to install it.&lt;/p>
&lt;/blockquote>
&lt;hr>
&lt;h2 id="4-building-configuration-files-postcss--tailwind-css">4. Building Configuration Files (PostCSS &amp;amp; Tailwind CSS)
&lt;/h2>&lt;p>Once the package installation is complete, create two important configuration files that control the project&amp;rsquo;s behavior. Place them in the project root directory.&lt;/p>
&lt;h3 id="creating-tailwindconfigjs">Creating tailwind.config.js
&lt;/h3>&lt;p>Run the following command in your terminal to generate the default configuration file.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">npx tailwindcss init
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Open the generated &lt;code>tailwind.config.js&lt;/code> in your editor and set the &lt;code>content&lt;/code> property. This is extremely important. Tailwind analyzes the files at the paths specified here and extracts the classes being used. Precisely specify the layout files and content files according to your Hugo project structure.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="cm">/** @type {import(&amp;#39;tailwindcss&amp;#39;).Config} */&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">module&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">exports&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Specify targets to scan according to Hugo&amp;#39;s directory structure
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">content&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;./content/**/*.md&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;./content/**/*.html&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;./layouts/**/*.html&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;./assets/**/*.js&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// If you are using a theme, you also need to include the theme&amp;#39;s directory
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// &amp;#34;./themes/my-theme/layouts/**/*.html&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">theme&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">extend&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Extend custom colors and fonts here
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">colors&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;brand-primary&amp;#39;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;#3490dc&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;brand-secondary&amp;#39;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;#ffed4a&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">fontFamily&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;sans&amp;#39;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;Helvetica Neue&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Arial&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Hiragino Kaku Gothic ProN&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;Meiryo&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;sans-serif&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">plugins&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Add official plugins as needed (e.g., Typography plugin)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// require(&amp;#39;@tailwindcss/typography&amp;#39;),
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="creating-postcssconfigjs">Creating postcss.config.js
&lt;/h3>&lt;p>Next, create &lt;code>postcss.config.js&lt;/code> in the project root, which defines which plugins PostCSS will run and in what order.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="nx">module&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">exports&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">plugins&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">tailwindcss&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">autoprefixer&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>With this configuration, when Hugo calls PostCSS, it will first apply Tailwind CSS processing and then use Autoprefixer to add vendor prefixes.&lt;/p>
&lt;hr>
&lt;h2 id="5-building-the-css-asset-pipeline-in-hugo">5. Building the CSS Asset Pipeline in Hugo
&lt;/h2>&lt;p>Once the configuration is complete, it is finally time to integrate Tailwind CSS into the Hugo theme side.&lt;/p>
&lt;h3 id="5-1-creating-the-entry-point-css-file">5-1. Creating the Entry Point CSS File
&lt;/h3>&lt;p>Create the entry point CSS file in the &lt;code>assets/css/&lt;/code> directory (create it if it doesn&amp;rsquo;t exist). We will name it &lt;code>main.css&lt;/code> here.&lt;/p>
&lt;p>&lt;strong>File Path: &lt;code>assets/css/main.css&lt;/code>&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-css" data-lang="css">&lt;span class="line">&lt;span class="cl">&lt;span class="c">/* Load Tailwind&amp;#39;s base styles (reset CSS, etc.) */&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">@&lt;/span>&lt;span class="k">tailwind&lt;/span> &lt;span class="nt">base&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">/* Load component classes */&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">@&lt;/span>&lt;span class="k">tailwind&lt;/span> &lt;span class="nt">components&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">/* Load utility classes */&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">@&lt;/span>&lt;span class="k">tailwind&lt;/span> &lt;span class="nt">utilities&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">/* If you need your own custom CSS, you can add it here,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"> but it is recommended to handle it in tailwind.config.js&amp;#39;s extend as much as possible */&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">@&lt;/span>&lt;span class="k">layer&lt;/span> &lt;span class="nt">components&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">.&lt;/span>&lt;span class="nc">btn-primary&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">@apply&lt;/span> &lt;span class="err">bg-blue-500&lt;/span> &lt;span class="n">hover&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="n">bg-blue-700&lt;/span> &lt;span class="kc">text&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="kc">white&lt;/span> &lt;span class="k">font&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="kc">bold&lt;/span> &lt;span class="n">py-2&lt;/span> &lt;span class="n">px-4&lt;/span> &lt;span class="n">rounded&lt;/span> &lt;span class="k">transition&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">colors&lt;/span> &lt;span class="n">duration-300&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="5-2-editing-the-layout-file-headhtml">5-2. Editing the Layout File (head.html)
&lt;/h3>&lt;p>Next, we will load the above CSS file from a Hugo template and write the pipeline to process it with PostCSS. Generally, you edit the partial template that defines the &lt;code>&amp;lt;head&amp;gt;&lt;/code> tag (e.g., &lt;code>layouts/partials/head.html&lt;/code>).&lt;/p>
&lt;p>&lt;strong>File Path: &lt;code>layouts/partials/head.html&lt;/code>&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-go-html-template" data-lang="go-html-template">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">head&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">charset&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;utf-8&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;viewport&amp;#34;&lt;/span> &lt;span class="na">content&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;width=device-width, initial-scale=1&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">title&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>&lt;span class="cp">{{&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="na">.Title&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="cp">}}&lt;/span> | &lt;span class="cp">{{&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="na">.Site.Title&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="cp">}}&lt;/span>&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">title&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c">&amp;lt;!-- Get assets/css/main.css --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="cp">{{&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nx">$css&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">:=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nx">resources&lt;/span>&lt;span class="na">.Get&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;css/main.css&amp;#34;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="cp">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c">&amp;lt;!-- Define PostCSS options --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="cp">{{&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nx">$options&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">:=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nx">dict&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;inlineImports&amp;#34;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">true&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="cp">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="cp">{{&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nx">$css&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nx">$css&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nx">resources&lt;/span>&lt;span class="na">.PostCSS&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nx">$options&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="cp">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c">&amp;lt;!-- Asset optimization pipeline for the Production environment --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="cp">{{&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">if&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nx">hugo&lt;/span>&lt;span class="na">.IsProduction&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="cp">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c">&amp;lt;!-- 1. Minify --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="cp">{{&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nx">$css&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nx">$css&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nx">minify&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="cp">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c">&amp;lt;!-- 2. Fingerprint (add hash for cache busting) --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="cp">{{&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nx">$css&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nx">$css&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nx">fingerprint&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;sha512&amp;#34;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="cp">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c">&amp;lt;!-- 3. Output the tag including SRI (Subresource Integrity) --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">link&lt;/span> &lt;span class="na">rel&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;stylesheet&amp;#34;&lt;/span> &lt;span class="na">href&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="cp">{{&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nx">$css&lt;/span>&lt;span class="na">.RelPermalink&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="cp">}}&lt;/span>&lt;span class="s">&amp;#34;&lt;/span> &lt;span class="na">integrity&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="cp">{{&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nx">$css&lt;/span>&lt;span class="na">.Data.Integrity&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="cp">}}&lt;/span>&lt;span class="s">&amp;#34;&lt;/span> &lt;span class="na">crossorigin&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;anonymous&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="cp">{{&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">else&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="cp">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c">&amp;lt;!-- In the Development environment, output as-is without minifying (prioritize build speed) --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">link&lt;/span> &lt;span class="na">rel&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;stylesheet&amp;#34;&lt;/span> &lt;span class="na">href&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="cp">{{&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nx">$css&lt;/span>&lt;span class="na">.RelPermalink&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="cp">}}&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="cp">{{&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">end&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="cp">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">head&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h4 id="pipeline-explanation-and-mermaid-diagram-illustration">Pipeline Explanation and Mermaid Diagram Illustration
&lt;/h4>&lt;p>We will diagrammatically explain the sequence of pipeline processing for how the above Go template code handles the CSS file.&lt;/p>
&lt;pre class="mermaid">
flowchart TD
A[&amp;#34;assets/css/main.css&amp;#34;] --&amp;gt;|resources.Get| B[&amp;#34;Hugo Memory Space&amp;#34;]
B --&amp;gt;|resources.PostCSS| C[&amp;#34;PostCSS + Tailwind JIT Process&amp;#34;]
C --&amp;gt; D{&amp;#34;hugo.IsProduction ?&amp;#34;}
D -- Yes (Production environment) --&amp;gt; E[&amp;#34;minify (remove spaces/newlines)&amp;#34;]
E --&amp;gt; F[&amp;#34;fingerprint (calculate hash)&amp;#34;]
F --&amp;gt; G[&amp;#34;public/css/main.[hash].css (with SRI)&amp;#34;]
D -- No (Development environment) --&amp;gt; H[&amp;#34;public/css/main.css&amp;#34;]
&lt;/pre>
&lt;ol>
&lt;li>&lt;strong>&lt;code>resources.Get&lt;/code>&lt;/strong>: Looks for the specified file within the &lt;code>assets&lt;/code> directory and loads it as a resource object in memory.&lt;/li>
&lt;li>&lt;strong>&lt;code>resources.PostCSS&lt;/code>&lt;/strong>: Refers to &lt;code>postcss.config.js&lt;/code> in the project root and applies Tailwind CSS and Autoprefixer processing to the CSS source code. In the development environment (&lt;code>hugo server&lt;/code>), JIT mode kicks in and rapidly generates only the necessary classes when files are modified.&lt;/li>
&lt;li>&lt;strong>&lt;code>minify&lt;/code>&lt;/strong>: During production builds (like &lt;code>hugo --environment production&lt;/code>), it removes unnecessary whitespace and comments to minimize the file size.&lt;/li>
&lt;li>&lt;strong>&lt;code>fingerprint&lt;/code>&lt;/strong>: Calculates a SHA hash based on the file&amp;rsquo;s contents and appends it to the filename (e.g., &lt;code>main.ab12cd...css&lt;/code>). This enables &amp;ldquo;cache busting,&amp;rdquo; allowing you to utilize strong browser caching while ensuring a new file is reliably loaded when the CSS is updated.&lt;/li>
&lt;li>&lt;strong>&lt;code>integrity&lt;/code>&lt;/strong>: Outputs an SRI attribute using the hash value calculated by Fingerprint to prevent tampering from CDNs and other sources.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="6-mathematical-performance-analysis-in-css-optimization">6. Mathematical Performance Analysis in CSS Optimization
&lt;/h2>&lt;p>One of the greatest benefits of introducing Tailwind CSS is the minimization of the delivered CSS file size. Let&amp;rsquo;s use a mathematical model to quantitatively analyze how this impacts web performance (especially First Contentful Paint: FCP).&lt;/p>
&lt;h3 id="css-file-size-reduction-model">CSS File Size Reduction Model
&lt;/h3>&lt;p>With traditional CSS frameworks (like Bootstrap), the entire volume is loaded, including unused styles, so the file size $S_{original}$ tends to be large (around 150KB to 200KB).
Let $S_{purged}$ be the size after purging unused classes with the Tailwind CSS JIT compiler, and $R_{purge}$ be the reduction rate. This can be expressed as follows:&lt;/p>
$$
S_{purged} = S_{original} \times (1 - R_{purge})
$$&lt;p>In a typical project, $R_{purge}$ reaches close to $0.9$ (a 90% reduction), and $S_{purged}$ fits into just around 10KB to 20KB.&lt;/p>
&lt;p>Furthermore, compression by Brotli or Gzip is performed on the server side upon delivery. Assuming a compression rate $R_{compress}$ (usually around 0.7 to 0.8), the final payload size $S_{final}$ flowing through the network is calculated with the following formula:&lt;/p>
$$
S_{final} = S_{purged} \times (1 - R_{compress})
$$&lt;h3 id="critical-rendering-path-and-network-latency">Critical Rendering Path and Network Latency
&lt;/h3>&lt;p>The time it takes for a browser to render the first piece of content on the screen (FCP) can be approximated as the sum of the HTML download time, CSS download time, and rendering time.&lt;/p>
$$
T_{FCP} \approx RTT + \frac{S_{HTML}}{BW} + RTT + \frac{S_{final}}{BW} + T_{render}
$$&lt;p>Where:&lt;/p>
&lt;ul>
&lt;li>$RTT$ : Round Trip Time (communication latency with the server)&lt;/li>
&lt;li>$BW$ : Network Bandwidth&lt;/li>
&lt;/ul>
&lt;p>In environments with narrow $BW$ and large $RTT$ (high latency) such as mobile networks, Tailwind CSS&amp;rsquo;s approach, which can strip $S_{final}$ down to mere kilobytes, pushes the $\frac{S_{final}}{BW}$ term extremely close to zero, acting as the driving force to achieve phenomenal scores (e.g., Google PageSpeed Insights).&lt;/p>
&lt;hr>
&lt;h2 id="7-starting-the-development-server-and-checking-hot-reloading">7. Starting the Development Server and Checking Hot Reloading
&lt;/h2>&lt;p>Once all configurations are complete, start the Hugo development server and check if Tailwind CSS is working properly.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">hugo server -D
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Access &lt;code>http://localhost:1313/&lt;/code> in your browser and verify that the site is displayed.
Try opening a Markdown content file or a Hugo template (files under &lt;code>layouts/&lt;/code>) and adding some classes.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="c">&amp;lt;!-- Example of applying Tailwind classes for testing --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">div&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;bg-gradient-to-r from-blue-500 to-purple-600 text-white p-8 rounded-xl shadow-2xl text-center transform transition duration-500 hover:scale-105&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">h1&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;text-4xl font-extrabold tracking-tight&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Tailwind CSS + Hugo is Awesome!&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">h1&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">p&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;mt-4 text-lg font-medium&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Please verify that hot reloading is instantly reflected.&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">p&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">div&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>The moment you save the file, Hugo&amp;rsquo;s powerful file watcher and Tailwind&amp;rsquo;s JIT compiler will work together to rebuild the CSS in milliseconds, allowing you to experience the thrill of the browser automatically reloading (hot reloading).&lt;/p>
&lt;h3 id="troubleshooting-when-styles-are-not-reflected">Troubleshooting: When Styles Are Not Reflected
&lt;/h3>&lt;p>If your changes are not reflected, check the following points.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>The &lt;code>content&lt;/code> path setting in &lt;code>tailwind.config.js&lt;/code>&lt;/strong>
If the scanned file paths are incorrect, Tailwind cannot detect the classes used within those files and will not output them to the CSS. Especially if you are using a theme, make sure the theme directory path is not missing.&lt;/li>
&lt;li>&lt;strong>PostCSS Errors&lt;/strong>
If an error like &lt;code>Error: failed to transform resource: PostCSS not found&lt;/code> appears in the Hugo server logs in your terminal, &lt;code>npm install&lt;/code> might not have executed correctly, or &lt;code>postcss-cli&lt;/code> might be missing.&lt;/li>
&lt;li>&lt;strong>Clearing the Hugo Cache&lt;/strong>
Rarely, old CSS remains due to Hugo&amp;rsquo;s cache. Try stopping the server and starting it with &lt;code>hugo server --ignoreCache&lt;/code>, or deleting the OS temporary directory (e.g., &lt;code>/tmp/hugo_cache/&lt;/code>).&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="8-production-builds-and-further-advancements">8. Production Builds and Further Advancements
&lt;/h2>&lt;p>When deploying your site to a production server (Netlify, Vercel, GitHub Pages, Cloudflare Pages, etc.), you need to set environment variables to run the production optimization pipeline.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Example of a production build command&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">NODE_ENV&lt;/span>&lt;span class="o">=&lt;/span>production hugo --minify --environment production
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>By adding the &lt;code>--environment production&lt;/code> flag, the &lt;code>{{ if hugo.IsProduction }}&lt;/code> block in &lt;code>head.html&lt;/code> is executed, and CSS minification and fingerprinting will take place.&lt;/p>
&lt;h3 id="styling-markdown-with-the-typography-plugin">Styling Markdown with the Typography Plugin
&lt;/h3>&lt;p>In blogs and documentation sites like those made with Hugo, you cannot directly add classes to pure HTML elements (&lt;code>&amp;lt;h1&amp;gt;&lt;/code>, &lt;code>&amp;lt;p&amp;gt;&lt;/code>, &lt;code>&amp;lt;ul&amp;gt;&lt;/code>, etc.) generated from Markdown. The official Tailwind &lt;strong>Typography plugin&lt;/strong> is extremely useful in such cases.&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Install the plugin&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">npm install -D @tailwindcss/typography
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;/li>
&lt;li>
&lt;p>Add it to &lt;code>tailwind.config.js&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="nx">module&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">exports&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// ...
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">plugins&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;@tailwindcss/typography&amp;#39;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;/li>
&lt;li>
&lt;p>Applying it in templates
Simply adding the &lt;code>prose&lt;/code> class (and your choice of color or size variants) to the container element that outputs the body of the article will apply beautiful default styles.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-go-html-template" data-lang="go-html-template">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">article&lt;/span> &lt;span class="na">class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;prose prose-lg prose-blue mx-auto mt-10&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="cp">{{&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="na">.Content&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="cp">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">article&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;/li>
&lt;/ol>
&lt;p>This completely eliminates the need to manually write complex CSS selectors (e.g., &lt;code>.article-content h2 { ... }&lt;/code>) and perfectly preserves component modularity.&lt;/p>
&lt;hr>
&lt;h2 id="9-conclusion-completing-a-highly-maintainable-frontend-ecosystem">9. Conclusion: Completing a Highly Maintainable Frontend Ecosystem
&lt;/h2>&lt;p>Great job. You have now completed a perfect web development asset pipeline, combining Hugo&amp;rsquo;s ultra-fast static site generation engine, Tailwind CSS&amp;rsquo;s modern styling capabilities, and PostCSS&amp;rsquo;s extensibility.&lt;/p>
&lt;p>The brilliance of this architecture is that &lt;strong>&amp;ldquo;you only have to configure it once.&amp;rdquo;&lt;/strong> Once the pipeline is built, developers never have to open a CSS file; by simply writing intuitive utility classes into HTML or Markdown templates, they can build complex UIs at astonishing speeds.&lt;/p>
&lt;p>Moreover, because the output CSS size is always minimized, it directly contributes to improving Core Web Vitals scores and works very advantageously from an SEO perspective.&lt;/p>
&lt;p>The combination of Hugo and Tailwind CSS will remain one of the &amp;ldquo;best choices&amp;rdquo; for every project, from personal tech blogs to large corporate websites. Please take advantage of this powerful toolchain and enjoy a comfortable web development life!&lt;/p></description></item><item><title>Introduction to Static Site Generators with Hugo (Migration Guide from WordPress)</title><link>http://kenji.blog/en/p/hugo-static-site-generator-wordpress-migration/</link><pubDate>Sun, 13 Sep 2026 02:00:00 +0900</pubDate><guid>http://kenji.blog/en/p/hugo-static-site-generator-wordpress-migration/</guid><description>&lt;img src="http://kenji.blog/p/hugo-static-site-generator-wordpress-migration/img/eyecatch.jpg" alt="Featured image of post Introduction to Static Site Generators with Hugo (Migration Guide from WordPress)" />&lt;p>In modern web development and blog management, site loading speed, security, and maintainability have become extremely crucial factors. For a long time, &amp;ldquo;WordPress&amp;rdquo; has boasted an overwhelming market share as the foundation for blogs and corporate sites, and is loved by many users for its flexible plugin ecosystem and intuitive admin interface. However, because it involves communication with a database and dynamic page generation on the server side (processed by PHP), it also faces challenges such as vulnerability to sudden traffic spikes and display delays (latency).&lt;/p>
&lt;p>Therefore, &amp;ldquo;Static Site Generators (SSG)&amp;rdquo; have been rapidly gaining popularity in recent years. In this article, among the many SSGs, we will delve deeply into &amp;ldquo;&lt;strong>Hugo&lt;/strong>&amp;rdquo;, which is developed in Go and known for its overwhelming build speed. We will thoroughly explain everything from the technical architecture comparison with dynamic CMS (Content Management System) like WordPress, to specific migration procedures, performance evaluation using mathematical models, and Hugo&amp;rsquo;s unique directory structure and template lookup order.&lt;/p>
&lt;hr>
&lt;h2 id="1-technical-differences-between-dynamic-cms-wordpress-and-static-site-generator-hugo">1. Technical Differences between Dynamic CMS (WordPress) and Static Site Generator (Hugo)
&lt;/h2>&lt;p>In the mechanism of delivering websites, WordPress and Hugo take fundamentally different approaches.&lt;/p>
&lt;h3 id="11-wordpress-architecture-dynamic-generation">1.1 WordPress Architecture (Dynamic Generation)
&lt;/h3>&lt;p>WordPress is a prime example of a dynamic CMS that assembles pages on the server side every time a request is made. When a user (browser) accesses a page, the web server (Apache, Nginx, etc.) executes PHP scripts and issues queries to a relational database like MySQL (or MariaDB). It combines the content fetched from the database (article data, categories, tags, site settings, etc.) with template files, generates the final HTML, and returns it to the client.&lt;/p>
&lt;p>This mechanism has the advantage of being able to generate different content in real-time for each visitor (e.g., e-commerce carts, pages exclusive to logged-in users), but unless caching mechanisms (reverse proxies, plugins, etc.) are properly designed, it aggressively consumes server resources.&lt;/p>
&lt;h3 id="12-hugo-architecture-pre-generation-at-build-time">1.2 Hugo Architecture (Pre-generation at Build Time)
&lt;/h3>&lt;p>On the other hand, Hugo, as the name &amp;ldquo;Static Site Generator&amp;rdquo; suggests, generates content not at &amp;ldquo;request time&amp;rdquo; but at &amp;ldquo;build time&amp;rdquo;. Content is maintained not in a database, but as local &amp;ldquo;Markdown files&amp;rdquo; version-controlled by Git, etc.
When a developer executes the command (&lt;code>hugo&lt;/code>), Hugo reads the Markdown files, pours the data into specified HTML templates (layout files), and generates a collection of completed, pure HTML/CSS/JS files.&lt;/p>
&lt;p>The generated files (static assets) can be delivered simply by placing them in a &amp;ldquo;static hosting environment&amp;rdquo; such as Amazon S3, Cloudflare Pages, Netlify, Vercel, or a simple Nginx server. Since neither a database nor a server-side language (like PHP) is required, security risks (like SQL injections and PHP vulnerabilities) are dramatically reduced, and delivery speed is maximized by being cached on edge nodes of a CDN (Content Delivery Network).&lt;/p>
&lt;p>Below, we show the differences in each architecture using a Mermaid diagram.&lt;/p>
&lt;pre class="mermaid">
flowchart TD
subgraph WordPress[&amp;#34;Dynamic CMS (WordPress)&amp;#34;]
direction TB
Req1[&amp;#34;User Request&amp;#34;] --&amp;gt; WebServer1[&amp;#34;Web Server (Nginx/Apache)&amp;#34;]
WebServer1 --&amp;gt; PHP[&amp;#34;PHP Processor&amp;#34;]
PHP &amp;lt;--&amp;gt; DB[&amp;#34;Database (MySQL)&amp;#34;]
PHP --&amp;gt; HTML1[&amp;#34;HTML Generation&amp;#34;]
HTML1 --&amp;gt; Res1[&amp;#34;Return Response&amp;#34;]
end
subgraph Hugo[&amp;#34;Static Site Generator (Hugo)&amp;#34;]
direction TB
Dev[&amp;#34;Developer / CI/CD&amp;#34;] --&amp;gt; HugoBuild[&amp;#34;Hugo Build Process&amp;#34;]
Markdown[&amp;#34;Markdown Files&amp;#34;] --&amp;gt; HugoBuild
Templates[&amp;#34;Templates (HTML)&amp;#34;] --&amp;gt; HugoBuild
HugoBuild --&amp;gt; StaticFiles[&amp;#34;Static Files (HTML/CSS/JS)&amp;#34;]
StaticFiles --&amp;gt; CDN[&amp;#34;CDN / Static Hosting&amp;#34;]
Req2[&amp;#34;User Request&amp;#34;] --&amp;gt; CDN
CDN --&amp;gt; Res2[&amp;#34;Return Immediate Response&amp;#34;]
end
&lt;/pre>
&lt;hr>
&lt;h2 id="2-performance-evaluation-using-mathematical-models">2. Performance Evaluation using Mathematical Models
&lt;/h2>&lt;p>One of the greatest benefits of migrating from WordPress to Hugo is the improvement in performance (load speed). To understand this quantitatively, let&amp;rsquo;s express it with a simple mathematical model.&lt;/p>
&lt;p>The time until page loading is complete (Load Time: $T_{load}$) is broadly divided into the server response time (TTFB: Time To First Byte) and the rendering/resource fetching time by the browser ($T_{render}$).&lt;/p>
$$ T_{load} = T_{ttfb} + T_{render} $$&lt;p>In the case of a dynamic CMS (WordPress), $T_{ttfb}$ is the sum of the following factors: network latency ($T_{network}$), server-side script execution time ($T_{php}$), and database query processing time ($T_{db}$).&lt;/p>
$$ T_{ttfb\_wp} = T_{network} + T_{php} + T_{db} $$&lt;p>Under heavy access conditions (high load), $T_{php}$ and $T_{db}$ increase non-linearly, and the entire system can become a bottleneck. Expressed as a formula, we see the following deterioration in response time relative to the number of requests ($N$) ($k$ is the processing overhead coefficient).&lt;/p>
$$ T_{php}(N) \approx O(N^k), \quad T_{db}(N) \approx O(N^k) \quad \text{where } k > 1 $$&lt;p>On the other hand, in an architecture combining a static site generator (Hugo) and a CDN, there are no server-side dynamic processes (PHP or DB queries). Because the content is cached on edge servers distributed globally, $T_{ttfb}$ purely depends on the network latency ($T_{edge}$) from the client to the nearest edge server.&lt;/p>
$$ T_{ttfb\_hugo} = T_{edge} $$&lt;p>As a result, $T_{edge} \ll (T_{network} + T_{php} + T_{db})$ holds true, and TTFB is dramatically reduced to just a few milliseconds to tens of milliseconds. Moreover, even if the number of requests $N$ increases, the response time remains almost constant ($O(1)$) due to the load-balancing capabilities of edge servers.&lt;/p>
$$ \lim_{N \to \infty} T_{ttfb\_hugo}(N) \approx \text{Constant} $$&lt;p>This is the mathematical basis for why Hugo (static sites) is extremely robust against traffic spikes (e.g., when content goes viral).&lt;/p>
&lt;hr>
&lt;h2 id="3-basic-structure-and-operating-principles-of-hugo">3. Basic Structure and Operating Principles of Hugo
&lt;/h2>&lt;p>To master Hugo, it is essential to understand its unique directory structure and the concepts of &amp;ldquo;Front Matter&amp;rdquo; and &amp;ldquo;Template Lookup Order&amp;rdquo;.&lt;/p>
&lt;h3 id="31-detailed-explanation-of-directory-structure">3.1 Detailed Explanation of Directory Structure
&lt;/h3>&lt;p>When you create a new Hugo project (&lt;code>hugo new site mysite&lt;/code>), the following directory structure is generated.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">mysite/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── archetypes/ # Templates when creating new content (Front Matter blueprints)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── assets/ # Files to be processed by Hugo Pipes (SCSS/Sass, JavaScript, etc.)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── content/ # Actual site content (Markdown files). This acts as a DB replacement.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── data/ # External data and settings used across the site (JSON, TOML, YAML, CSV, etc.)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── layouts/ # HTML templates that determine the site&amp;#39;s appearance (using Go html/template)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── public/ # Where generated static files are output after running the build command
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── static/ # Static files published as-is (images, favicons, robots.txt, etc.)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── themes/ # Third-party or custom theme directories
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└── hugo.toml # Site-wide configuration file (config.toml was mainstream previously)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>In WordPress, content is stored in the &lt;code>wp_posts&lt;/code> table of MySQL, but in Hugo, everything is managed as text files (mainly Markdown) in the &lt;code>content/&lt;/code> directory. This makes version control (Git) of content easy.&lt;/p>
&lt;h3 id="32-content-management-markdown-and-front-matter">3.2 Content Management: Markdown and Front Matter
&lt;/h3>&lt;p>Each article file in Hugo has a metadata block at the very top called &amp;ldquo;Front Matter&amp;rdquo;, followed by the body text (Markdown) below it. Front Matter can be written in TOML, YAML, or JSON, but YAML is widely used.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">title&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;Understanding Hugo Taxonomy&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">date&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="ld">2026-09-13T10:00:00&lt;/span>&lt;span class="m">+09&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="m">00&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">draft&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">false&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">categories&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;Technical Guide&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">tags&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;Hugo&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;Go&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">aliases&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;/old-category/hugo-taxonomy/&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="l">The body text starts here. Written in **Markdown**.&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="l">We will explain the powerful features of Hugo...&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>What&amp;rsquo;s noteworthy here is the &lt;code>aliases&lt;/code> key. When migrating from WordPress, if permalinks (URLs) change, it causes a significant negative impact on SEO. By using Hugo&amp;rsquo;s alias feature, you just specify the old URL, and Hugo will automatically generate an HTML file for redirection (forwarding via meta refresh). This is very convenient as it eliminates the need for server-side redirection settings (like .htaccess).&lt;/p>
&lt;h3 id="33-template-lookup-order">3.3 Template Lookup Order
&lt;/h3>&lt;p>One of Hugo&amp;rsquo;s powerful features is its flexible template discovery mechanism (Template Lookup Order). When rendering a specific page, Hugo searches directories and filenames in a specific order to find the most appropriate template.&lt;/p>
&lt;p>For example, when rendering a single article (Single Page) like &lt;code>content/post/hello-world.md&lt;/code>, Hugo looks for the layout file in roughly the following order:&lt;/p>
&lt;ol>
&lt;li>&lt;code>layouts/post/single.html&lt;/code>&lt;/li>
&lt;li>&lt;code>layouts/post/list.html&lt;/code> (Not an error, but usually for lists)&lt;/li>
&lt;li>&lt;code>layouts/_default/single.html&lt;/code>&lt;/li>
&lt;li>&lt;code>themes/&amp;lt;THEME_NAME&amp;gt;/layouts/post/single.html&lt;/code>&lt;/li>
&lt;li>&lt;code>themes/&amp;lt;THEME_NAME&amp;gt;/layouts/_default/single.html&lt;/code>&lt;/li>
&lt;/ol>
&lt;p>Developers can &lt;strong>override&lt;/strong> theme templates simply by creating a file with the same name in their project&amp;rsquo;s &lt;code>layouts/&lt;/code> directory, without directly modifying the theme&amp;rsquo;s source code. This allows you to apply your own customizations without hindering updates to the base theme.&lt;/p>
&lt;h3 id="34-taxonomy">3.4 Taxonomy
&lt;/h3>&lt;p>The classification system corresponding to &amp;ldquo;Categories&amp;rdquo; and &amp;ldquo;Tags&amp;rdquo; in WordPress is called &amp;ldquo;Taxonomy&amp;rdquo; in Hugo.
Hugo supports &lt;code>categories&lt;/code> and &lt;code>tags&lt;/code> taxonomies by default, but you can freely add custom taxonomies (e.g., &lt;code>series&lt;/code>, &lt;code>authors&lt;/code>, etc.) by editing &lt;code>hugo.toml&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># hugo.toml example&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">taxonomies&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">category&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;categories&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">tag&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;tags&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">series&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;series&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">author&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;authors&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>This makes it possible to organize and list content along diverse axes.&lt;/p>
&lt;hr>
&lt;h2 id="4-migration-process-from-wordpress-to-hugo-migration">4. Migration Process from WordPress to Hugo (Migration)
&lt;/h2>&lt;p>The key to a successful migration from WordPress to Hugo is how to cleanly convert dynamic content in the database into static files (Markdown + Front Matter) while maintaining the existing URL structure.&lt;/p>
&lt;p>Below is the flow of a typical migration pipeline.&lt;/p>
&lt;pre class="mermaid">
flowchart LR
WPDB[&amp;#34;WP Database&amp;#34;] --&amp;gt;|Plugin| Exporter[&amp;#34;Export Tool&amp;#34;]
Exporter --&amp;gt;| Extracts Text, \nMeta, Images | ZipFile[&amp;#34;Zip / Folder&amp;#34;]
ZipFile --&amp;gt;|Unpack| MarkdownFiles[&amp;#34;Markdown Files \n(content/)&amp;#34;]
ZipFile --&amp;gt;|Unpack| ImageFiles[&amp;#34;Images \n(static/wp-content/)&amp;#34;]
MarkdownFiles --&amp;gt; Formatting[&amp;#34;Review &amp;amp; Format \n(Fix Shortcodes)&amp;#34;]
Formatting --&amp;gt; Git[&amp;#34;Commit to Git&amp;#34;]
&lt;/pre>
&lt;h3 id="41-data-extraction-and-markdown-conversion">4.1 Data Extraction and Markdown Conversion
&lt;/h3>&lt;p>To output WordPress data for Hugo, using a dedicated plugin is the easiest and most reliable method. Here are a few typical approaches.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Using the Jekyll Exporter Plugin&lt;/strong>
Since Hugo has a very similar data structure to Jekyll, another SSG, it is a common practice to use the &amp;ldquo;Jekyll Exporter&amp;rdquo; plugin for WordPress. When you install and run this plugin, all posts and static pages are converted into Markdown files with Front Matter, and can be downloaded as a ZIP file along with image files.&lt;/li>
&lt;li>&lt;strong>Custom Script utilizing the WordPress API&lt;/strong>
This is a method of writing a script in Python, Node.js, etc., that calls the WordPress REST API (&lt;code>/wp-json/wp/v2/posts&lt;/code>), parses the JSON data, and generates Markdown files yourself. It is effective for sites that heavily use complex custom fields (like ACF) that plugins cannot fully handle.&lt;/li>
&lt;li>&lt;strong>Utilizing the wp2hugo Tool&lt;/strong>
There is also an approach using CLI tools written in Go, etc., to convert directly from WordPress export XML files (WXR) to Hugo format.&lt;/li>
&lt;/ol>
&lt;h3 id="42-maintaining-permalink-url-structure">4.2 Maintaining Permalink (URL) Structure
&lt;/h3>&lt;p>To carry over your SEO evaluation, it is extremely important to maintain the URLs from your WordPress era. If you had permalink settings like &lt;code>https://example.com/2026/09/13/my-post/&lt;/code> in WordPress, you specify the permalink structure in Hugo&amp;rsquo;s &lt;code>hugo.toml&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-toml" data-lang="toml">&lt;span class="line">&lt;span class="cl">&lt;span class="p">[&lt;/span>&lt;span class="nx">permalinks&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">post&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;/:year/:month/:day/:slug/&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Alternatively, you can forcibly fix the URL by specifying the &lt;code>url&lt;/code> parameter directly in the Front Matter for each article.
Furthermore, for pages where the URL changes, set up redirects using the aforementioned &lt;code>aliases&lt;/code>.&lt;/p>
&lt;h3 id="43-converting-shortcodes">4.3 Converting Shortcodes
&lt;/h3>&lt;p>WordPress-specific shortcodes (e.g., &lt;code>[gallery]&lt;/code>, &lt;code>[caption]&lt;/code>, proprietary codes of various plugins) often remain as raw strings when exported, so they need to be addressed.
These can be bulk-deleted using a replacement script (sed or Python), or migrated so they are rendered properly on the Hugo side by utilizing Hugo&amp;rsquo;s powerful &lt;strong>custom shortcode feature&lt;/strong> (creating custom layouts in &lt;code>layouts/shortcodes/&lt;/code>).&lt;/p>
&lt;hr>
&lt;h2 id="5-hugo-cli-tools-and-builddeployment">5. Hugo CLI Tools and Build/Deployment
&lt;/h2>&lt;p>Once the migration work is complete, it&amp;rsquo;s finally time to build the site using Hugo and publish it to the world. Hugo, provided as a Go binary, boasts astonishing speed, completing builds in just seconds even for sites with thousands or tens of thousands of pages.&lt;/p>
&lt;h3 id="51-starting-the-local-development-server">5.1 Starting the Local Development Server
&lt;/h3>&lt;p>When writing articles or adjusting designs, you start a local server.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Command to start the development server (-D to include draft articles)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">hugo server -D
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Running this command allows you to preview the site at &lt;code>http://localhost:1313/&lt;/code>. Hugo has a powerful built-in &amp;ldquo;LiveReload&amp;rdquo; feature; the moment you edit and save a Markdown file, template, or CSS, the browser screen is automatically and rapidly updated. This makes the writing and development experience far more comfortable than the WordPress admin interface.&lt;/p>
&lt;h3 id="52-production-build-and-performance-optimization">5.2 Production Build and Performance Optimization
&lt;/h3>&lt;p>To generate static files for deploying to a production environment, simply type &lt;code>hugo&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Execute production build. --minify option minifies HTML/CSS/JS&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">hugo --minify
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>This command outputs the entire site&amp;rsquo;s files to the &lt;code>public/&lt;/code> directory. By adding the &lt;code>--minify&lt;/code> option, unnecessary line breaks and spaces are removed, further reducing file sizes. This directly contributes to reducing the network latency ($T_{network}$) in the mathematical model mentioned earlier.&lt;/p>
&lt;h3 id="53-automating-deployment-cicd">5.3 Automating Deployment (CI/CD)
&lt;/h3>&lt;p>Generating static files locally on your PC every time and uploading them via FTP, etc., is inefficient. In modern SSG operations, the best practice is to build a CI/CD environment that automatically builds and deploys triggered by pushes to a Git repository (like GitHub).&lt;/p>
&lt;p>For example, the basic structure of a configuration (YAML file) for deploying to Cloudflare Pages or GitHub Pages using GitHub Actions looks like this.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Example of .github/workflows/hugo.yml&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Deploy Hugo site to GitHub Pages&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">push&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">branches&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;main&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">workflow_dispatch&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">permissions&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">contents&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">read&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">pages&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">write&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">id-token&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">write&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">jobs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">build&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">runs-on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ubuntu-latest&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Checkout&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">actions/checkout@v3&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">with&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">submodules&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">recursive&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># If themes are managed as submodules&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">fetch-depth&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">0&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Setup Hugo&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">peaceiris/actions-hugo@v2&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">with&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">hugo-version&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;latest&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">extended&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Build&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">run&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">hugo --minify&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Upload artifact&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">actions/upload-pages-artifact@v2&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">with&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">path&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">./public&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">deploy&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">environment&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">github-pages&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">url&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${{ steps.deployment.outputs.page_url }}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">runs-on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ubuntu-latest&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">needs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">build&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Deploy to GitHub Pages&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">id&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">deployment&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">uses&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">actions/deploy-pages@v2&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>By configuring this, just the action of &amp;ldquo;writing an article in Markdown and pushing it to GitHub&amp;rdquo; completes an automated pipeline where the latest site is published to the production environment in a few minutes.&lt;/p>
&lt;hr>
&lt;h2 id="6-post-migration-seo-and-operational-benefits">6. Post-Migration SEO and Operational Benefits
&lt;/h2>&lt;p>Site operators who have completed the migration from WordPress to Hugo often experience the following three prominent benefits.&lt;/p>
&lt;h3 id="61-dramatic-improvement-in-site-speed-and-core-web-vitals">6.1 Dramatic Improvement in Site Speed and Core Web Vitals
&lt;/h3>&lt;p>As a result of eliminating database queries and server-side rendering, page load times are reduced to milliseconds. This directly leads to a significant improvement in &amp;ldquo;Core Web Vitals&amp;rdquo; (LCP, FID/INP, CLS) scores, which are Google ranking factors. A decrease in user bounce rate and an improvement in SEO evaluation can be expected.&lt;/p>
&lt;h3 id="62-freedom-from-security-threats">6.2 Freedom from Security Threats
&lt;/h3>&lt;p>Because WordPress is widely used worldwide, it is constantly a target for attacks. It is always accompanied by risks such as defacement exploiting plugin vulnerabilities and login breaches via brute-force attacks.
However, static sites generated by Hugo do not have a database, PHP environment, or even an admin screen (login form). There is no room for hackers to invade the server and rewrite the database, and security risks approach absolute zero.&lt;/p>
&lt;h3 id="63-maintenance-free-operation">6.3 Maintenance-Free Operation
&lt;/h3>&lt;p>Operating WordPress requires constant maintenance work, such as updating the core, updating plugins, and keeping up with PHP versions. You must constantly fear the risk of your site breaking due to compatibility issues.
With Hugo, you only need to update the tool itself as necessary, and since the site&amp;rsquo;s code itself is an independent set of text files, there is an overwhelming sense of security that &amp;ldquo;it won&amp;rsquo;t break even if left alone&amp;rdquo;.&lt;/p>
&lt;hr>
&lt;h2 id="7-conclusion">7. Conclusion
&lt;/h2>&lt;p>In this article, we thoroughly explained the migration from a dynamic CMS like WordPress to the powerful Go-based static site generator &amp;ldquo;Hugo&amp;rdquo;, covering everything from technical architecture differences and performance proofs using mathematical models, to specific migration procedures.&lt;/p>
&lt;p>While migrating to a static site generator requires an initial learning cost (Git operations, Markdown syntax, executing CLI commands from a terminal, understanding template engine specifications, etc.), it brings returns that more than compensate for it: &amp;ldquo;overwhelming display speed&amp;rdquo;, &amp;ldquo;robust security&amp;rdquo;, and &amp;ldquo;maintenance-free&amp;rdquo; operation.&lt;/p>
&lt;p>If your website does not require frequent design changes or complex dynamic processing (such as member-only features or advanced e-commerce functions) and is mainly intended for information dissemination (blogs, media, corporate sites), migrating to Hugo will be one of the most effective technical investments you can make. By all means, use this article as a reference to take your first step towards next-generation website management with Hugo.&lt;/p></description></item><item><title>Hugo Blog SEO: Frontmatter Settings to Dramatically Increase Traffic</title><link>http://kenji.blog/en/p/hugo-blog-seo-frontmatter-tips/</link><pubDate>Sat, 12 Sep 2026 12:00:00 +0900</pubDate><guid>http://kenji.blog/en/p/hugo-blog-seo-frontmatter-tips/</guid><description>&lt;img src="http://kenji.blog/p/hugo-blog-seo-frontmatter-tips/img/eyecatch.jpg" alt="Featured image of post Hugo Blog SEO: Frontmatter Settings to Dramatically Increase Traffic" />&lt;p>Hugo is one of the world&amp;rsquo;s fastest static site generators (SSG) written in Go. Its overwhelming build speed and flexible template system have garnered high support from many engineers and bloggers. However, simply generating and displaying a site quickly is not enough to be highly evaluated by search engines (like Google or Bing) and deliver articles to users.&lt;/p>
&lt;p>To improve search rankings, increase diffusion power on social media, and consequently dramatically increase blog traffic, meticulous SEO (Search Engine Optimization) measures are essential. The heart of SEO in Hugo is the integration of the &lt;strong>Frontmatter&lt;/strong>, which is written at the beginning of each markdown article, and the &lt;strong>Layouts&lt;/strong> (templates), which interpret it and expand metadata into the &lt;code>&amp;lt;head&amp;gt;&lt;/code> tag of the HTML.&lt;/p>
&lt;p>In this article, we will thoroughly explain in an overwhelming volume of over 10,000 characters how to maximize Hugo&amp;rsquo;s functions and implement advanced SEO measures, ranging from frontmatter settings to various meta tags, OGP (Open Graph Protocol), Twitter Cards, and outputting structured data using JSON-LD.&lt;/p>
&lt;hr>
&lt;h2 id="1-mathematical-background-of-seo-and-traffic">1. Mathematical Background of SEO and Traffic
&lt;/h2>&lt;p>Before diving into specific implementations, let&amp;rsquo;s mathematically understand why detailed SEO metadata is important. The search traffic $T$ that a website can acquire is determined by the search volume of the target keyword and the Click-Through Rate (CTR) based on the search ranking.&lt;/p>
&lt;p>This can be expressed by the following formula:&lt;/p>
$$ T = \sum_{i=1}^{n} V_i \times CTR(R_i) $$&lt;ul>
&lt;li>$V_i$ : Monthly search volume for keyword $i$&lt;/li>
&lt;li>$R_i$ : Search ranking for keyword $i$&lt;/li>
&lt;li>$CTR(R_i)$ : Click-Through Rate at ranking $R_i$&lt;/li>
&lt;/ul>
&lt;p>Among these, the search ranking $R_i$ depends on many factors such as content quality and backlinks (PageRank), but Google&amp;rsquo;s early PageRank algorithm is modeled as follows:&lt;/p>
$$ PR(u) = \frac{1-d}{N} + d \sum_{v \in B(u)} \frac{PR(v)}{L(v)} $$&lt;ul>
&lt;li>$PR(u)$ : PageRank of page $u$&lt;/li>
&lt;li>$d$ : Damping factor (usually 0.85)&lt;/li>
&lt;li>$B(u)$ : Set of pages linking to page $u$&lt;/li>
&lt;li>$L(v)$ : Number of outbound links from page $v$&lt;/li>
&lt;/ul>
&lt;p>What&amp;rsquo;s important here is &lt;strong>how to maximize the click-through rate $CTR(R_i)$ in addition to the effort to raise the search ranking $R_i$&lt;/strong>. By optimizing titles and snippets (description) displayed on search results (SERPs) and eyecatch images (OGP) when shared on social media, it is possible to intentionally raise $CTR(R_i)$. SEO settings in frontmatter are directly linked to maximizing this $CTR$.&lt;/p>
&lt;hr>
&lt;h2 id="2-hugos-build-process-and-the-role-of-frontmatter">2. Hugo&amp;rsquo;s Build Process and the Role of Frontmatter
&lt;/h2>&lt;p>Hugo reads the frontmatter (YAML/TOML/JSON) in the markdown file and passes it to the template engine as page variables. Let&amp;rsquo;s first understand this flow of information visually.&lt;/p>
&lt;pre class="mermaid">
flowchart TD
A[&amp;#34;Markdown File&amp;#34;] --&amp;gt; B[&amp;#34;Frontmatter Parsing&amp;#34;]
A --&amp;gt; C[&amp;#34;Content Parsing&amp;#34;]
B --&amp;gt; D[&amp;#34;Hugo Page Variables (.Title, .Params)&amp;#34;]
C --&amp;gt; D
E[&amp;#34;layouts/partials/head.html&amp;#34;] --&amp;gt; F[&amp;#34;Go Template Engine&amp;#34;]
D --&amp;gt; F
F --&amp;gt; G[&amp;#34;Final HTML &amp;lt;head&amp;gt; Tag&amp;#34;]
G --&amp;gt; H[&amp;#34;Googlebot / Crawlers&amp;#34;]
G --&amp;gt; I[&amp;#34;Social Media Scrapers (OGP)&amp;#34;]
&lt;/pre>
&lt;p>In this way, the values set in the frontmatter are passed to &lt;code>head.html&lt;/code> as variables like &lt;code>.Title&lt;/code> and &lt;code>.Params.description&lt;/code>, and output as the final HTML metadata. Therefore, SEO success consists of two steps: &amp;ldquo;defining appropriate information in the frontmatter&amp;rdquo; and &amp;ldquo;correctly converting it to HTML with templates&amp;rdquo;.&lt;/p>
&lt;hr>
&lt;h2 id="3-basic-metadata-settings-title-description-canonical-url">3. Basic Metadata Settings: Title, Description, Canonical URL
&lt;/h2>&lt;p>The most basic tags for search engines to understand page content are &lt;code>&amp;lt;title&amp;gt;&lt;/code> and &lt;code>&amp;lt;meta name=&amp;quot;description&amp;quot;&amp;gt;&lt;/code>. Also, &lt;code>&amp;lt;link rel=&amp;quot;canonical&amp;quot;&amp;gt;&lt;/code> is essential to avoid penalties for duplicate content.&lt;/p>
&lt;h3 id="31-frontmatter-setting-example">3.1. Frontmatter Setting Example
&lt;/h3>&lt;p>We prepare fields specialized for SEO in the article&amp;rsquo;s frontmatter.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">title&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;Hugo Blog SEO: Frontmatter Settings to Dramatically Increase Traffic&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">seo_title&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;Complete Guide to Hugo SEO: Boost Traffic with Frontmatter&amp;#34;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># Optional: For search engines&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">description&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;Advanced SEO techniques utilizing Hugo frontmatter. A detailed explanation of OGP, JSON-LD, and metadata settings.&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">slug&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;hugo-seo-frontmatter-tips&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">canonicalUrl&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;https://example.com/post/hugo-seo-frontmatter-tips/&amp;#34;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># Explicit canonical URL&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="32-implementation-of-layoutspartialsheadhtml">3.2. Implementation of &lt;code>layouts/partials/head.html&lt;/code>
&lt;/h3>&lt;p>We create an HTML template to correctly output these variables.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="c">&amp;lt;!-- Title optimization --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ $title := .Title }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ if .Params.seo_title }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> {{ $title = .Params.seo_title }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ end }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">title&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>{{ $title }} | {{ .Site.Title }}&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">title&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&amp;lt;!-- Description optimization --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ $description := .Summary | plainify | truncate 120 }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ if .Params.description }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> {{ $description = .Params.description }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ end }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;description&amp;#34;&lt;/span> &lt;span class="na">content&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;{{ $description }}&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&amp;lt;!-- Canonical URL (Normalization) --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ $canonical := .Permalink }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ if .Params.canonicalUrl }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> {{ $canonical = .Params.canonicalUrl }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ end }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">link&lt;/span> &lt;span class="na">rel&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;canonical&amp;#34;&lt;/span> &lt;span class="na">href&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;{{ $canonical }}&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&amp;lt;!-- Robot control (e.g., noindex settings) --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ if .Params.noindex }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;robots&amp;#34;&lt;/span> &lt;span class="na">content&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;noindex, nofollow&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ else }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;robots&amp;#34;&lt;/span> &lt;span class="na">content&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;index, follow&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ end }}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>By using Hugo&amp;rsquo;s &lt;code>.Summary&lt;/code> as a fallback, even if &lt;code>description&lt;/code> is not set, the introductory text of the article can be automatically extracted.&lt;/p>
&lt;hr>
&lt;h2 id="4-ogp-and-twitter-cards-maximizing-ctr-on-social-media">4. OGP and Twitter Cards: Maximizing CTR on Social Media
&lt;/h2>&lt;p>To display articles in an attractive card format when shared on SNS like Twitter (X) and Facebook, Open Graph Protocol (OGP) and Twitter Cards settings are indispensable. This is also dynamically generated from the frontmatter.&lt;/p>
&lt;h3 id="41-issues-with-built-in-templates">4.1. Issues with Built-in Templates
&lt;/h3>&lt;p>Hugo has a convenient built-in template &lt;code>{{ template &amp;quot;_internal/opengraph.html&amp;quot; . }}&lt;/code>, but it lacks customizability and may not fit specific requirements or Japanese environments. Therefore, we strongly recommend implementing your own OGP tags within &lt;code>head.html&lt;/code>.&lt;/p>
&lt;h3 id="42-specifying-images-in-frontmatter">4.2. Specifying Images in Frontmatter
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;img/eyecatch.jpg&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">images&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;img/eyecatch-large.jpg&amp;#34;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># For multiple images or absolute paths&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="43-custom-implementation-code-for-ogp-and-twitter-cards">4.3. Custom Implementation Code for OGP and Twitter Cards
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="c">&amp;lt;!-- Open Graph Protocol --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">property&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;og:title&amp;#34;&lt;/span> &lt;span class="na">content&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;{{ $title }}&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">property&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;og:description&amp;#34;&lt;/span> &lt;span class="na">content&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;{{ $description }}&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">property&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;og:type&amp;#34;&lt;/span> &lt;span class="na">content&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;{{ if .IsPage }}article{{ else }}website{{ end }}&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">property&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;og:url&amp;#34;&lt;/span> &lt;span class="na">content&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;{{ .Permalink }}&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">property&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;og:site_name&amp;#34;&lt;/span> &lt;span class="na">content&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;{{ .Site.Title }}&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&amp;lt;!-- Resolving OGP Image --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ $ogImage := &amp;#34;&amp;#34; }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ if .Params.image }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> {{ $ogImage = .Params.image | absURL }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ else if .Params.images }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> {{ $ogImage = index .Params.images 0 | absURL }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ else if .Site.Params.defaultImage }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> {{ $ogImage = .Site.Params.defaultImage | absURL }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ end }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ if $ogImage }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">property&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;og:image&amp;#34;&lt;/span> &lt;span class="na">content&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;{{ $ogImage }}&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;twitter:image&amp;#34;&lt;/span> &lt;span class="na">content&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;{{ $ogImage }}&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;twitter:card&amp;#34;&lt;/span> &lt;span class="na">content&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;summary_large_image&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ else }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;twitter:card&amp;#34;&lt;/span> &lt;span class="na">content&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;summary&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ end }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&amp;lt;!-- Twitter Cards --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;twitter:title&amp;#34;&lt;/span> &lt;span class="na">content&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;{{ $title }}&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;twitter:description&amp;#34;&lt;/span> &lt;span class="na">content&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;{{ $description }}&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ if .Site.Params.twitterAccount }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">meta&lt;/span> &lt;span class="na">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;twitter:site&amp;#34;&lt;/span> &lt;span class="na">content&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;@{{ .Site.Params.twitterAccount }}&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ end }}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>By interposing the &lt;code>absURL&lt;/code> function, an image URL specified by a relative path is converted to an absolute path. Since absolute paths are mandatory in OGP, this process is extremely important.&lt;/p>
&lt;hr>
&lt;h2 id="5-implementation-of-structured-data-json-ld">5. Implementation of Structured Data (JSON-LD)
&lt;/h2>&lt;p>In current SEO, &lt;strong>JSON-LD (JavaScript Object Notation for Linked Data)&lt;/strong> has become mainstream as a technology to accurately convey the semantic structure of a page to search engines. By setting this up, rich snippets (star ratings, author name, publication date, etc.) are more likely to be displayed in search results.&lt;/p>
&lt;h3 id="51-structure-of-json-ld">5.1. Structure of JSON-LD
&lt;/h3>&lt;p>For blog articles, two main schemas are implemented: the &lt;code>Article&lt;/code> schema and the &lt;code>BreadcrumbList&lt;/code> schema.&lt;/p>
&lt;pre class="mermaid">
flowchart TD
A[&amp;#34;Schema.org Definitions&amp;#34;] --&amp;gt; B[&amp;#34;Article Schema&amp;#34;]
A --&amp;gt; C[&amp;#34;BreadcrumbList Schema&amp;#34;]
B --&amp;gt; D[&amp;#34;headline&amp;#34;]
B --&amp;gt; E[&amp;#34;datePublished&amp;#34;]
B --&amp;gt; F[&amp;#34;dateModified&amp;#34;]
B --&amp;gt; G[&amp;#34;author&amp;#34;]
B --&amp;gt; H[&amp;#34;image&amp;#34;]
C --&amp;gt; I[&amp;#34;ListItem 1&amp;#34;]
C --&amp;gt; J[&amp;#34;ListItem 2&amp;#34;]
I --&amp;gt; K[&amp;#34;position: 1&amp;#34;]
I --&amp;gt; L[&amp;#34;name: Home&amp;#34;]
J --&amp;gt; M[&amp;#34;position: 2&amp;#34;]
J --&amp;gt; N[&amp;#34;name: Category / Blog&amp;#34;]
&lt;/pre>
&lt;h3 id="52-json-ld-generation-in-hugo-templates">5.2. JSON-LD Generation in Hugo Templates
&lt;/h3>&lt;p>Leverage frontmatter variables like &lt;code>.Date&lt;/code> and &lt;code>.Lastmod&lt;/code> to dynamically output JSON-LD. Describe it in &lt;code>head.html&lt;/code> using the &lt;code>&amp;lt;script type=&amp;quot;application/ld+json&amp;quot;&amp;gt;&lt;/code> tag.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">{{ if .IsPage }}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">script&lt;/span> &lt;span class="na">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;application/ld+json&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@context&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;https://schema.org&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@type&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;Article&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;mainEntityOfPage&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@type&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;WebPage&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@id&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;{{ .Permalink }}&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;headline&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;{{ .Title | htmlEscape }}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;description&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;{{ $description | htmlEscape }}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;image&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;{{ $ogImage }}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;datePublished&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;{{ .Date.Format &amp;#34;&lt;/span>&lt;span class="mi">2006&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">01&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">02&lt;/span>&lt;span class="nx">T15&lt;/span>&lt;span class="o">:&lt;/span>&lt;span class="mi">04&lt;/span>&lt;span class="o">:&lt;/span>&lt;span class="mi">05&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">07&lt;/span>&lt;span class="o">:&lt;/span>&lt;span class="mi">00&lt;/span>&lt;span class="s2">&amp;#34; }}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;dateModified&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;{{ .Lastmod.Format &amp;#34;&lt;/span>&lt;span class="mi">2006&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">01&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">02&lt;/span>&lt;span class="nx">T15&lt;/span>&lt;span class="o">:&lt;/span>&lt;span class="mi">04&lt;/span>&lt;span class="o">:&lt;/span>&lt;span class="mi">05&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">07&lt;/span>&lt;span class="o">:&lt;/span>&lt;span class="mi">00&lt;/span>&lt;span class="s2">&amp;#34; }}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;author&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@type&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;Person&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;{{ if .Params.author }}{{ .Params.author }}{{ else }}{{ .Site.Params.author }}{{ end }}&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;publisher&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@type&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;Organization&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;{{ .Site.Title }}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;logo&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@type&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;ImageObject&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;url&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;{{ .Site.Params.logo | absURL }}&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">script&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&amp;lt;!-- BreadcrumbList Schema --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">script&lt;/span> &lt;span class="na">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;application/ld+json&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@context&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;https://schema.org&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@type&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;BreadcrumbList&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;itemListElement&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@type&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;ListItem&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;position&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;Home&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;item&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;{{ .Site.BaseURL }}&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{{&lt;/span> &lt;span class="nx">$position&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="p">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{{&lt;/span> &lt;span class="nx">range&lt;/span> &lt;span class="p">.&lt;/span>&lt;span class="nx">Params&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">categories&lt;/span> &lt;span class="p">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">,{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@type&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;ListItem&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;position&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{{&lt;/span> &lt;span class="nx">$position&lt;/span> &lt;span class="p">}},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;{{ . }}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;item&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;{{ &amp;#34;&lt;/span>&lt;span class="nx">categories&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="s2">&amp;#34; | relLangURL }}{{ . | urlize | lower }}/&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{{&lt;/span> &lt;span class="nx">$position&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">add&lt;/span> &lt;span class="nx">$position&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="p">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{{&lt;/span> &lt;span class="nx">end&lt;/span> &lt;span class="p">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">,{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@type&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;ListItem&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;position&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{{&lt;/span> &lt;span class="nx">$position&lt;/span> &lt;span class="p">}},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;{{ .Title | htmlEscape }}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;item&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;{{ .Permalink }}&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">script&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">{{ end }}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>When expanding strings within JSON-LD, the key is to use &lt;code>htmlEscape&lt;/code> (or &lt;code>jsonify&lt;/code>) to prevent breaking the double quotes. This prevents JSON syntax errors regardless of what symbols are used in the frontmatter.&lt;/p>
&lt;hr>
&lt;h2 id="6-advanced-techniques-for-utilizing-frontmatter">6. Advanced Techniques for Utilizing Frontmatter
&lt;/h2>&lt;p>In addition to basic SEO metadata, Hugo&amp;rsquo;s frontmatter has features to realize more advanced SEO strategies.&lt;/p>
&lt;h3 id="61-redirect-processing-via-aliases">6.1. Redirect Processing via Aliases
&lt;/h3>&lt;p>If you have migrated to Hugo from a past blog service or changed the structure of permalinks, you need to redirect access from the old URLs to the new URLs. By using the &lt;code>aliases&lt;/code> field in Hugo, you can automatically generate HTTP-Equiv refresh (meta redirect) pages for the old URLs.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">title&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;New Article Title&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">slug&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;new-seo-post&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">aliases&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;/old-category/old-seo-post/&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="s2">&amp;#34;/2020/05/12/seo-tips/&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="62-article-expiration-dates-and-scheduling">6.2. Article Expiration Dates and Scheduling
&lt;/h3>&lt;p>For limited-time campaign articles or information that loses value as it gets older, setting an &lt;code>expiryDate&lt;/code> makes it possible to exclude them from the build results and not display them on the site (to return a 404) after a specific date and time. This prevents low-quality, outdated content from remaining in the index and lowering the overall evaluation of the site.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">title&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;Exclusive SEO Techniques for 2026&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">publishDate&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;2026-01-01T00:00:00Z&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">expiryDate&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;2026-12-31T23:59:59Z&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nn">---&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="7-site-performance-and-core-web-vitals">7. Site Performance and Core Web Vitals
&lt;/h2>&lt;p>In SEO, &lt;strong>page loading speed&lt;/strong> is just as important as tag optimization. Google incorporates Core Web Vitals (LCP, FID/INP, CLS) as ranking factors.&lt;/p>
&lt;p>Hugo, which is a static site, originally has excellent TTFB (Time to First Byte), but image optimization is mandatory for blogs that use a lot of images. By combining Hugo&amp;rsquo;s powerful Image Processing feature with frontmatter, conversion to Next-gen formats (such as WebP) and resizing can be automated at build time.&lt;/p>
&lt;p>For example, you can create a shortcode that automatically generates WebP images on the template side from the image path specified in the frontmatter. This can dramatically increase your SEO evaluation.&lt;/p>
&lt;hr>
&lt;h2 id="8-conclusion">8. Conclusion
&lt;/h2>&lt;p>In blog operations using Hugo, the frontmatter is not just an &amp;ldquo;enumeration of configuration values&amp;rdquo; but a &amp;ldquo;control panel&amp;rdquo; for interacting with search engines and SNS.&lt;/p>
&lt;p>By completely implementing the following points explained in this article, the SEO foundation of your blog will become solid.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Dynamic Generation of Basic Metadata&lt;/strong>: Reliable output of Title, Description, and Canonical.&lt;/li>
&lt;li>&lt;strong>Optimization of Social Sharing&lt;/strong>: CTR improvement through custom implementation of OGP and Twitter Cards.&lt;/li>
&lt;li>&lt;strong>Full Support for Structured Data&lt;/strong>: Rich result support through JSON-LD (Article, Breadcrumb).&lt;/li>
&lt;li>&lt;strong>Advanced Traffic Management&lt;/strong>: Robot control with meta tags and redirects using Aliases.&lt;/li>
&lt;/ol>
&lt;p>Search engine algorithms are evolving daily, but the fundamental principle of SEO, which is to provide signals for search engines to &amp;ldquo;correctly understand the content of the page&amp;rdquo;, remains unchanged. By mastering Hugo&amp;rsquo;s flexible template engine and frontmatter, continue to broadcast those signals with the highest quality, and dramatically increase your blog&amp;rsquo;s traffic.&lt;/p></description></item></channel></rss>