Right, let’s talk about making your data play nice with others. In any template, you’re constantly juggling types. Hugo pulls your data from all sorts of places—front matter, data files, site configurations—and it doesn’t always arrive in the format you need. That’s where this toolkit of conversion functions comes in. They’re your Swiss Army knife for politely, or sometimes forcefully, asking a value to be something else.

The Basics: int, float, and string

These are your workhorses. They do exactly what you’d expect, but with a few Hugo-specific quirks you need to know about.

The int function will convert a string or a float into an integer. It’s great for when you get a numeric string from a CSV or TOML file and need to do math with it.

{{ "123" | int }}{{/* outputs the number 123, not the string "123" */}}
{{ 45.99 | int }}{{/* outputs 45. It truncates; it doesn't round. Harsh but fair. */}}

Its sibling float does the same but for floating-point numbers.

{{ "3.14159" | float }}{{/* outputs the float 3.14159 */}}
{{ 42 | float }}{{/* outputs 42.0 */}}

Now, string is the most forgiving of the bunch. It will convert anything to a string. A number? Sure. A boolean? You get “true” or “false”. A whole slice of data? Hold my beer.

{{ 42 | string }}{{/* "42" */}}
{{ true | string }}{{/* "true" */}}
{{ slice "a" "b" "c" | string }}{{/* "[a b c]" */}} Wait, what?

Ah, yes. The last one. When you pass a slice (like an array) to string, Hugo doesn’t magically concatenate it. It returns a string representation of the slice itself, which looks like [a b c]. This is a common “gotcha.” To combine a slice of strings into a single string, you’d use delimit, not string.

jsonify: Your Data’s Passport

This is arguably one of the most useful functions in Hugo’s arsenal. jsonify converts a given object into a JSON string. It’s your go-to for shipping data out of Hugo’s world and into JavaScript’s, whether you’re initializing a variable in a <script> tag or using Hugo as a headless CMS API endpoint.

<script>
    const siteData = {{ .Site.Data | jsonify }};
    // Renders as: const siteData = {"menu":{"items":[...]}};
</script>

The beauty of jsonify is its simplicity. It handles the escaping for you. Those pesky quotes, newlines, and special characters in your content? They’re all properly escaped so your JSON isn’t invalid and doesn’t break your entire page. Always use jsonify when outputting data for JavaScript. Concatenating strings manually is a one-way ticket to bug city.

You can also pretty-print it for debugging purposes, which is a lifesaver.

{{ .Site.Data | jsonify (dict "indent" "  ") }}

unmarshal: The Bouncer at the JSON Club

unmarshal is jsonify’s inverse. It takes a JSON string and converts it back into a structured data object that Hugo’s templates can understand and iterate over. Think of it as a way to embed portable, structured data inside your front matter or in a content file.

Why would you do this? Let’s say you have a complex, repeating set of properties for a page. Instead of trying to force it into TOML’s or YAML’s syntax, you can just write a JSON string and unmarshal it.

# In your content file front matter
jsonData: '{"features": ["Fast", "Flexible", "Fun"], "score": 95}'
{{ $data := .Params.jsonData | unmarshal }}
<h3>Features:</h3>
<ul>
{{ range $data.features }}
    <li>{{ . }}</li>
{{ end }}
</ul>
<p>Score: {{ $data.score }}</p>

The major pitfall here: The JSON string must be perfectly valid. If it’s malformed, unmarshal will return nil and your template will silently break. No error message, just nothing. It’s brutal. I test my JSON strings in a validator before I put them in my content. You should too.

Best Practices and Pitfalls

  1. Know Your Source: Before you convert, know what you’re starting with. Use printf "%T" $value to debug a value’s type ($value is a string, int, etc.). You can’t fix a problem you don’t understand.
  2. jsonify for JS, Always: Never, ever try to manually output data into a JavaScript context. The escaping jsonify provides is non-negotiable for security and correctness.
  3. Test Your JSON: If you’re using unmarshal, validate the JSON string externally first. Hugo’s silent failure on error is its greatest weakness here.
  4. int Truncates: Don’t expect int to round your floats. It lops off the decimal. Use math.Round first if you need proper rounding.
  5. string isn’t delimit: Remember, converting a slice to a string gives you a debug-style output. To join elements, you want delimit $slice ", ".

These functions are less about flashy features and more about creating sturdy, reliable connections between the different parts of your site. Use them wisely, and you’ll avoid a whole class of frustrating template errors.