UUID v7
It’s common to use a UUID when you need a primary key for your database records. Unlike incrementing numeric keys, it has the advantage that it’s not tied to a specific database instance and can be created before insertion into the database.
Usually, people use version 4 UUIDs, which contains a lot of randomness to ensure that it’s going to be unique and not clash with any other id.
Recently, I became aware of version 7 UUIDs which became a standard with RFC 9562 in May 2024. These are very similar to UUIDv4, except that the first part is a timestamps which makes them time-sortable. This makes them much easier to use with time-based queries and are also more intuitive as the last one is the most recent.
One problem I’ve had is creating a UUIDv7 quickly and simply. For UUIDv4, I use uuidgen:
$ uuidgen
045E1A7B-870B-4635-98EA-9B94EBD0B769
Usually, I use this with a text-substitution macro so that I can just type ;uuid and it’s replaced with a shiny UUIDv4.
I wanted the same for UUIDv7s, but a quick google didn’t show up a nice simple binary that I could use. So I wrote my own, unimaginatively called uuid7.
This is the world’s simplest Go application that’s a wrapper around gofrs/uuid, by The Go Commune. This library does all the work and if you remove the boilerplate for help and version parameters, the code boils down to:
package main
import (
"fmt"
"log"
"github.com/gofrs/uuid/v5"
)
func main() {
u7, err := uuid.NewV7()
if err != nil {
log.Fatalf("failed to generate UUID: %v", err)
}
fmt.Printf("%v\n", u7)
}
I compiled it and put the resultant uuid7 binary in /usr/local/bin and now have a simple ;u7 text-substitution macro that generates a UUIDv7 for me:
$ uuid7
0191701c-da51-749a-a4fc-e96579ebc043
I picked Go because I ended up with a statically compiled application with no additional dependencies which makes it easier to deal with. You can also cross-compile, so I’ve created binaries for a variety of operating systems on the release page should you want to just download it. The macOS binaries are not notarised by Apple though, so requires more effort to initially set up. One day I’ll work out how to solve this.