Hugo Custom Go Template Development

Our company is engaged in the development, support and maintenance of sites of any complexity. From simple one-page sites to large-scale cluster systems built on micro services. Experience of developers is confirmed by certificates from vendors.
Development and maintenance of all types of websites:
Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:
Development stages
Latest works
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    822
  • image_crm_chasseurs_493_0.webp
    CRM development for Chasseurs
    847
  • image_website-sbh_0.png
    Website development for SBH Partners
    999
  • image_website-_0.png
    Website development for Red Pear
    451

Custom Hugo Template Development (Go Templates)

Hugo uses the standard html/template package from Go's standard library, extended with its own functions. The syntax differs from Twig, Jinja2, Liquid — it has its own logic that needs to be understood once, then work efficiently. A custom template gives you full control over markup without dependence on third-party themes.

Template Structure

Hugo resolves templates by lookup order. For a page /blog/my-post/, Hugo searches for a template in this order:

layouts/blog/single.html
layouts/blog/single.baseof.html
layouts/_default/single.html
layouts/_default/baseof.html

For a section /services/ (list of pages):

layouts/services/list.html
layouts/_default/list.html

The base template baseof.html defines structure through blocks:

{{/* layouts/_default/baseof.html */}}
<!DOCTYPE html>
<html lang="{{ .Site.Language.Lang }}">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>{{ block "title" . }}{{ .Site.Title }}{{ end }}</title>
  {{ block "head" . }}{{ end }}
  {{ partial "head/styles.html" . }}
</head>
<body class="{{ block "body-class" . }}{{ end }}">
  {{ partial "header.html" . }}
  <main>
    {{ block "main" . }}{{ end }}
  </main>
  {{ partial "footer.html" . }}
  {{ partial "head/scripts.html" . }}
</body>
</html>

A child template overrides blocks:

{{/* layouts/blog/single.html */}}
{{ define "title" }}{{ .Title }} | {{ .Site.Title }}{{ end }}

{{ define "body-class" }}page-post{{ end }}

{{ define "main" }}
<article class="post">
  <header class="post__header">
    <h1>{{ .Title }}</h1>
    <time datetime="{{ .Date.Format "2006-01-02" }}">
      {{ .Date.Format "2 January 2006" }}
    </time>
    {{ with .Params.authors }}
    <div class="post__authors">
      {{ range . }}
        {{ $author := index $.Site.Data.authors . }}
        <span>{{ $author.name }}</span>
      {{ end }}
    </div>
    {{ end }}
  </header>

  {{ if .Params.featured_image }}
  <figure class="post__cover">
    {{ $img := resources.Get .Params.featured_image }}
    {{ if $img }}
      {{ $webp := $img | images.Resize "1200x630 WebP" }}
      {{ $fallback := $img | images.Resize "1200x630" }}
      <picture>
        <source srcset="{{ $webp.Permalink }}" type="image/webp">
        <img src="{{ $fallback.Permalink }}" alt="{{ .Title }}" loading="eager">
      </picture>
    {{ end }}
  </figure>
  {{ end }}

  <div class="post__body">{{ .Content }}</div>

  {{ partial "blog/related-posts.html" . }}
</article>
{{ end }}

Working with Data and Variables

Go Templates are strictly typed. Main patterns:

{{/* Variable assignment */}}
{{ $total := 0 }}
{{ range .Pages }}
  {{ $total = add $total 1 }}
{{ end }}
Total posts: {{ $total }}

{{/* Working with dictionaries */}}
{{ $meta := dict "og:type" "article" "og:title" .Title }}
{{ range $key, $val := $meta }}
  <meta property="{{ $key }}" content="{{ $val }}">
{{ end }}

{{/* Conditions with AND/OR */}}
{{ if and .Params.featured (not .Draft) }}
  <span class="badge">Featured</span>
{{ end }}

{{/* Ternary operator via cond */}}
{{ $class := cond .Params.dark "section--dark" "section--light" }}
<section class="{{ $class }}">

Partial Functions with Parameters

Partials accept context (.) or arbitrary dictionaries:

{{/* Call partial with custom context */}}
{{ partial "components/card.html" (dict
  "title" .Title
  "url" .Permalink
  "image" .Params.thumbnail
  "excerpt" .Summary
  "date" .Date
  "tags" .Params.tags
) }}
{{/* layouts/partials/components/card.html */}}
{{ $ctx := . }}
<article class="card">
  {{ with $ctx.image }}
  <div class="card__image">
    <img src="{{ . }}" alt="{{ $ctx.title }}">
  </div>
  {{ end }}
  <div class="card__body">
    <h3 class="card__title">
      <a href="{{ $ctx.url }}">{{ $ctx.title }}</a>
    </h3>
    {{ with $ctx.excerpt }}
    <p class="card__excerpt">{{ . }}</p>
    {{ end }}
    {{ if $ctx.tags }}
    <ul class="card__tags">
      {{ range $ctx.tags }}
      <li><a href="/tags/{{ . | urlize }}/">{{ . }}</a></li>
      {{ end }}
    </ul>
    {{ end }}
  </div>
</article>

Custom Pages with Complex Logic

Example: team page with grouping by departments:

{{/* layouts/team/list.html */}}
{{ define "main" }}
{{ $pages := .Pages.ByParam "order" }}

{{/* Grouping by department */}}
{{ $departments := slice }}
{{ range $pages }}
  {{ $dept := .Params.department }}
  {{ if not (in $departments $dept) }}
    {{ $departments = $departments | append $dept }}
  {{ end }}
{{ end }}

{{ range $departments }}
  {{ $dept := . }}
  <section class="team-department">
    <h2>{{ $dept }}</h2>
    <div class="team-grid">
      {{ range where $pages "Params.department" $dept }}
        {{ partial "components/team-card.html" . }}
      {{ end }}
    </div>
  </section>
{{ end }}
{{ end }}

SEO Templates

{{/* layouts/partials/head/seo.html */}}
{{ $title := cond .IsHome .Site.Title (printf "%s | %s" .Title .Site.Title) }}
{{ $description := cond .Params.description .Params.description .Site.Params.description }}
{{ $image := cond .Params.featured_image .Params.featured_image .Site.Params.defaultOGImage }}

<title>{{ $title }}</title>
<meta name="description" content="{{ $description }}">

<meta property="og:title" content="{{ $title }}">
<meta property="og:description" content="{{ $description }}">
<meta property="og:url" content="{{ .Permalink }}">
<meta property="og:type" content="{{ if .IsPage }}article{{ else }}website{{ end }}">
{{ with $image }}
<meta property="og:image" content="{{ absURL . }}">
{{ end }}

{{ if .IsPage }}
<meta property="article:published_time" content="{{ .Date.Format "2006-01-02T15:04:05Z07:00" }}">
<meta property="article:modified_time" content="{{ .Lastmod.Format "2006-01-02T15:04:05Z07:00" }}">
{{ range .Params.tags }}
<meta property="article:tag" content="{{ . }}">
{{ end }}
{{ end }}

<link rel="canonical" href="{{ .Permalink }}">

{{ range .AlternativeOutputFormats }}
<link rel="{{ .Rel }}" type="{{ .MediaType.Type }}" href="{{ .Permalink | safeURL }}">
{{ end }}

Template Performance

Hugo caches partial results via partialCached:

{{/* Cache by page slug */}}
{{ partialCached "components/sidebar.html" . .Page.Slug }}

{{/* Cache globally (once for entire site) */}}
{{ partialCached "components/footer-nav.html" . }}

partialCached is especially important for partials that do heavy computations or access large datasets.

Timeline

Custom template for a site with 5–15 pages, blog, and basic SEO markup — 1–2 weeks. Complex template with multiple content types, custom taxonomies, multilingual support — 3–5 weeks.