Arithmetic and Comparison
Hugo doesn't support symbols like + or <. You need to use function calls for these operations.
{{ add 1 1 }}
{{ sub 2 1 }}
{{ mul 2 2 }}
{{ div 4 2 }}
{{ eq 1 1 }}
{{ ne 1 2 }}
{{ lt 1 2 }}
{{ le 2 2 }}
{{ gt 3 2 }}
{{ ge 2 2 }}2
1
4
2
true
true
true
true
true
trueif / else if / else
The basic if-else syntax. false, an empty string, 0, nil, an empty slice, and an empty dict are all falsy values.
{{ $x := 7 }}
{{ if eq $x 6 }}
eq 6
{{ else if eq $x 7 }}
eq 7
{{ else }}
...
{{ end }}eq 7with / else with
if only evaluates a condition without changing the context. with does both: it evaluates the condition and switches the context to that value.
{{ $v1 := "" }}
{{ $v2 := "Orange" }}
{{ with $v1 }}
{{ . }}
{{ else with $v2 }}
{{ . }}
{{ else }}
Neither
{{ end }}Orangeand / or / not
Logical operators.
{{ and true false }}
{{ or true false }}
{{ not false }}false
true
truerange
range works like a for loop. Hugo only has for loops, not while loops.
{{ range slice "Apple" "Banana" "Orange" }}
{{ . }}<br>
{{ end }}Apple<br>
Banana<br>
Orange<br>You can also include an index:
{{ range $idx, $val := slice "Apple" "Banana" "Orange" }}
{{ $idx }}: {{ $val }}<br>
{{ end }}0: Apple<br>
1: Banana<br>
2: Orange<br>break / continue
continue skips the current iteration. break ends the loop entirely.
{{ range slice "Apple" "Banana" "Orange" }}
{{ if eq . "Banana" }}
{{ continue }}
{{ end }}
{{ if eq . "Orange" }}
{{ break }}
{{ end }}
{{ . }}
{{ end }}Appleslice
A slice is a list. Use index to retrieve an element and len to get its length.
{{ $s := slice 1 2 3 4 5 6 7 8 9 10 }}
{{ index $s 0 }}
{{ len $s }}1
10To grab a range, use first and after together:
{{ $s | first 5 | after 2 }}[3 4 5]seq
Creates a list. seq N produces integers from 1 to N. seq A B produces integers from A to B.
{{ range seq 3 }}{{ . }}{{ end }}
{{ range seq 2 5 }}{{ . }}{{ end }}123
2345dict
A dict (map) holds key-value pairs. You can access a key with dot notation, which works the same as index.
{{ $person := dict "name" "John" "age" 20 }}
{{ index $person "name" }}
{{ $person.name }}John
JohnAccessing a key that doesn't exist won't throw an error.
cast
Type conversion.
{{ $s := "42" }}
{{ $n := cast.ToInt $s }}
{{ add $n 8 }}50add "42" 8 throws a type error, because add requires both operands to be numbers. You need to convert the string with cast.ToInt first.
partial and return
partial calls a template file.
Syntax
{{ partial LAYOUT CONTEXT }}Description
A partial is a standalone template file. When you call a template (LAYOUT) with the partial function, CONTEXT becomes the . inside that file.
{{ if lt . 100 }}
<span>On sale</span>
{{ else }}
<span>Regular price</span>
{{ end }}{{ partial "price-tag.html" 80 }}<span>On sale</span>If a template doesn't include return, Hugo renders it as HTML. If it does, Hugo returns that value instead:
{{ return lt . 100 }}{{ $cheap := partial "is-cheap.html" 80 }}
{{ print $cheap }}trueBefore v0.166.0, a partial only supported a single return.
Passing Multiple Values
partial only accepts a single CONTEXT argument. If you need to pass both a weight and a city, wrap them into one value with dict:
{{ if ge .weight 5 }}
{{ .city }}: extra shipping fee applies
{{ else }}
{{ .city }}: standard shipping fee
{{ end }}{{ partial "shipping-note.html" (dict "weight" 6 "city" "TX") }}TX: extra shipping fee applies.weight and .city correspond to the keys you passed in the dict call.
Inline Definitions
Use define to write a partial directly inside the template that calls it:
{{ partial "inline" 21 }}
{{ define "_partials/inline/double" }}
{{ mul . 2 }}
{{ end }}42Hugo scans all available templates before rendering, so inline definitions have no ordering requirements. An inline-defined template can be called from anywhere on the site.
Passing Values Between Templates
Templates can only pass values to each other through the CONTEXT you pass in {{ partial "foo.html" CONTEXT }}, or by using .Store: set a value with .Store.Set and retrieve it with .Store.Get.
partialCached
partialCached calls a template and caches its output.
Syntax
{{ partialCached LAYOUT CONTEXT [KEY1 KEY2 KEY3 ...] }}Description
When a LAYOUT produces repeated output and rendering it has become a performance bottleneck, use partialCached instead of partial to cache the output and avoid recomputing it.
KEY1, KEY2, KEY3, and so on are optional additional cache keys. They let the same LAYOUT produce multiple cached results depending on conditions. These extra keys don't participate in the template's own computation. They're only used to distinguish cached results, and you can supply zero or more of them.
If you don't specify any additional cache keys, the cache key defaults to the LAYOUT itself (that is, the partial's name).
Hugo renders multiple pages in parallel. The first time a given cache key is called, Hugo hasn't finished storing that key yet, so other pages rendering in parallel before that point will each render the same template independently. Once the cache key is stored, subsequent calls use the cached result directly.
Each site's cache is independent.
.Store
Everything covered so far has been a function. .Store is a method instead, and methods are bound to an object, which is why you see a . in front of it.
.Store stores content on a target object, letting you pass values between templates. You can call .Store on any of these objects:
| Scope | Usage |
|---|---|
| Entire site build | hugo.Store |
| Current site1 | SITE.Store |
| Current page | PAGE.Store |
| Shortcode | SHORTCODE.Store |
| Local variable | collections.NewScratch |
.Store is order-dependent. If you call .Get before ever calling .Store, .Get returns nothing.
Content stored in .Store persists for the entire build process. It doesn't get cleaned up just because the current page finishes rendering.
.Store exposes many methods you can call. The methods are the same regardless of which object .Store is bound to.
Example: Page Initialization
If a page requires elaborate initialization and the result needs to be shared across multiple templates, you can run that initialization at the top of baseof.html and store the result with .Page.Store. Every partial can then retrieve it through .Store.
<!doctype html>
{{- partial "init.html" . -}}
<html>
...
</html>{{- with resource.Get "..." -}}
{{- ... -}}
{{- .Page.Store.Set "key" ... -}}
{{- end -}}{{ with .Page.Store.Get "key" }}
{{ ... }}
{{ end }}{{ with .Page.Store.Get "key" }}
{{ ... }}
{{ end }}Example: Call Counting
Track how many times a shortcode was called on the same page.
{{ $count := .Page.Store.Get "imageCounter" | default 0 }}
{{ $count = add $count 1 }}
{{ .Page.Store.Set "imageCounter" $count }}
<figure id="img-{{ $count }}">
<img src="{{ .Get "src" }}" alt="{{ .Get "alt" }}">
</figure>If you only need to check whether a shortcode was called, without counting, use the .Page.HasShortcode method instead. Unlike .Store, this method has no ordering requirement, because Hugo scans the Markdown document ahead of time. That means you can call .Page.HasShortcode before the shortcode is actually rendered.
Example: Resource Loading
A common pattern is calling .Page.Store.Set to record that a feature was used on a page, then using .Page.Store.Get afterward to run the corresponding logic. A classic example is Mermaid diagrams in the official documentation.
See Sites Matrix for what "current site" means. ↩︎