logo hsb.horse
← Back to blog index

Blog

UUID v7 implementation guide: Create with JavaScript, Go, and Shell

The bit structure of UUID v7, bit settings of version/variant, minimum implementation in JavaScript, Go, and Shell, check items during implementation, and RFC references are organized on one page. A practical guide that summarizes the points to check in the generation logic for developers who want to safely introduce IDs that are easy to sort in time series. It can be used for confirmation before implementation.

Published: Updated:

We will summarize only the essential points needed when implementing UUID v7.
In this article, you can check the bit structure of UUID v7, how to set version/variant, and the minimum implementation in JavaScript, Go, and Shell.

UUID v7 essentials

UUID v7 is 128 bits with a millisecond timestamp at the beginning.

FieldNumber of BitsRole
timestamp48Unix time (ms)
ver40111 (v7)
rand_a12Random value
var210 (variant)
rand_b62Random value

With this configuration, it is possible to create IDs that are generally easy to sort in order of generation time.

Common steps during implementation

  1. First, fill 16 bytes with random numbers
  2. Overwrite the first 6 bytes with the current time (milliseconds)
  3. Set 0x7 (version) in the upper 4 bits of value[6]
  4. Set 10 (variant) to the upper 2 bits of value[8]

JavaScript / TypeScript implementation example

function uuidV7Bytes(): Uint8Array {
const value = new Uint8Array(16);
crypto.getRandomValues(value);
const timestamp = BigInt(Date.now());
value[0] = Number((timestamp >> 40n) & 0xffn);
value[1] = Number((timestamp >> 32n) & 0xffn);
value[2] = Number((timestamp >> 24n) & 0xffn);
value[3] = Number((timestamp >> 16n) & 0xffn);
value[4] = Number((timestamp >> 8n) & 0xffn);
value[5] = Number(timestamp & 0xffn);
value[6] = (value[6] & 0x0f) | 0x70;
value[8] = (value[8] & 0x3f) | 0x80;
return value;
}

Go implementation example

package main
import (
"crypto/rand"
"fmt"
"time"
)
func uuidV7() ([16]byte, error) {
var value [16]byte
if _, err := rand.Read(value[:]); err != nil {
return value, err
}
timestamp := uint64(time.Now().UnixMilli())
value[0] = byte(timestamp >> 40)
value[1] = byte(timestamp >> 32)
value[2] = byte(timestamp >> 24)
value[3] = byte(timestamp >> 16)
value[4] = byte(timestamp >> 8)
value[5] = byte(timestamp)
value[6] = (value[6] & 0x0F) | 0x70
value[8] = (value[8] & 0x3F) | 0x80
return value, nil
}
func main() {
id, _ := uuidV7()
fmt.Printf("%x\n", id)
}

Shell Script implementation example

#!/bin/sh
uuid_v7() {
timestamp=$(date +%s)000
timestamp_hi=$((timestamp >> 16))
timestamp_lo=$((timestamp & 0xFFFF))
rand_a=0x$(LC_ALL=C tr -dc '0-9a-f' < /dev/urandom | head -c4)
ver_rand_a=$((0x7000 | (0x0FFF & rand_a)))
rand_b_hi=0x$(LC_ALL=C tr -dc '0-9a-f' < /dev/urandom | head -c4)
var_rand_hi=$((0x8000 | (0x3FFF & rand_b_hi)))
rand_b_lo=$(LC_ALL=C tr -dc '0-9a-f' < /dev/urandom | head -c12)
printf "%08x-%04x-%04x-%04x-%s\n" \
"$timestamp_hi" "$timestamp_lo" "$ver_rand_a" "$var_rand_hi" "$rand_b_lo"
}
uuid_v7

POSIX date cannot directly handle milliseconds, so the acquisition method needs to be adjusted depending on the implementation environment.

Implementation check items

  • Evaluate the collision risk when generating a large amount within the same millisecond
  • Standardize the format (hyphenated string or 16 bytes) on the user side
  • Decide the DB index strategy (time series sorting assumption) first

Reference materials (external)

summary

The implementation of UUID v7 in any language centers on “timestamp embedding + version/variant bit manipulation”.
Depending on your requirements, you can choose between using an existing library or creating a minimal implementation in-house.