Generating Random Numbers, Strings, and more in Hugo
If you’ve ever needed a random number, string, or slice index from your Hugo website, this post has you covered. This article will cover selecting seeds, generating random numbers, and then how to use the random number to create random strings and select random items from slices.
Random numbers in Hugo (at least with the methods outlined in this tutorial) won’t generate a cryptographically secure value. I don’t see much worth generating cryptographically secure values for a static site.
Random Number
Most of the methods below will require you to generate a random number, or at the very least, have a seed value. You’ll need a seed, which is typically a Unix timestamp. Using a consistent seed within a page will give you the same random number sequence, which may be useful in some cases.
{{ $seed := now.Unix }}
Using the timestamp without additional equations might be “random” enough in some situations. Below is a linear congruential pseudo-random number generator. Every time you need a random number, you should change the seed to the value of the last random number you generated.
{{ $seed := now.Unix }}
{{ $rnd := {{ mod (add (mul 13 $seed) 97) 400000}} }}
You’ll usually see randomly generated numbers applied as the dividend of the modulus to select a value within a specific range.
Random Item in Slice
A slice is a data structure similar to an array. The difference between a slice and an array is that a slice can change in size. You can access items in a slice
by using the index
function within Hugo.
We can randomly sort a slice using the built-in function shuffle
and then obtain a random value from the first index.
{{ $slice := slice "a" "b" "c" "d" }}
{{ $shuffled := shuffle $slice }}
{{ $random := index $shuffled 0 }}
Seeded Random Items in Slice
To consistently grab the same random item from a slice, you need to generate a seed that will be consistent within that context but unique to its siblings.
This method is implemented on GeekThis to grab a random affiliate for each post. This method ensures that each time we build our site, that post’s affiliate doesn’t change.
You’ll need to find a seed that will be consistent for each page but unique across pages. For our use, we used the post’s initial publication date. Look at the section below about different methods of generating seeds.
{{ $seed := .Date.Unix }}
{{ $slice := slice "a" "b" "c" "d" }}
{{ $item := index $slice (mod $seed (len $slice)) }}
The above code will grab a random item from the slice. We get a random index by setting the modulus dividend to the seed and the length of the slice as the divisor.
The random item will be consistent between builds unless you change the date of the post. You can always use a different seed method to get different results.
Random String
You can turn your seed into a random string using the sha256
, md5
, or base64Encode
functions. With sha256
and md5
, the resulting string will be a hexadecimal hash of our seed. Using base64Encode
, you’ll get an alphanumeric encoding.
{{ $seed := now.Unix }}
{{ md5 $seed }}
{{ sha256 $seed }}
{{ base64Encode $seed }}
You can use printf
to shorten the string by setting the precision.
{{ printf "%.10s" (sha256 $seed) }}
If you’re generating random strings for your CSS and JavaScript filenames, you might want to look into fingerprinting. With fingerprinting, your file will have a unique string appended to the filename by Hugo.
Different Seed Methods
Below are a few different methods to obtain seeds that you can use with all of the above methods of generating random content. Each method has its advantages and will give you different results based on when the seed changes.
Date and Time
Using the current epoch is a simple way to seed pseudo-random number generators and is outlined earlier in this article. This seed will change with each build.
{{ $seed := now.Unix }}
File Hash
You can use any file hash from your project. Depending on how often this file is modified, the seed may be consistent or varied. This is a good seed to use if you’re trying to get repeatable results between builds but want different pages to have random values.
{{ $seed := int ( printf "0x%.8s" (md5 (readFile .File.Path))) }}
Git Commit Hash
Using the latest git commit hash/checksum, you can get unique seeds that are repeatable per commit. Each time you make a new commit your random values will change.
{{ $seed := int ( printf "0x%.8s" .GitInfo.Hash) }}
File’s UniqueID
The file’s UniqueID
is the MD5 hash of the file’s path and name. If you want a seed unique to each file, this is a good option.
{{ $seed := int ( printf "0x%.8s" .File.UniqueID) }}
What is Int Printf %.8s?
A few of the above functions may look a bit like gibberish. When you have a hexadecimal string, you can turn it into an integer with int
if you prefix the string with “0x”. We can’t turn 128bits into an integer, that’s where we trim the string to 32 bits (each byte is two characters).