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.
| Field | Number of Bits | Role |
|---|---|---|
timestamp | 48 | Unix time (ms) |
ver | 4 | 0111 (v7) |
rand_a | 12 | Random value |
var | 2 | 10 (variant) |
rand_b | 62 | Random 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
- First, fill 16 bytes with random numbers
- Overwrite the first 6 bytes with the current time (milliseconds)
- Set
0x7(version) in the upper 4 bits ofvalue[6] - Set
10(variant) to the upper 2 bits ofvalue[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_v7POSIX 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
Related links (inside the site)
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.
hsb.horse