uuid

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 15, 2026 License: MIT Imports: 9 Imported by: 0

README

CI Go Reference Go Report Card

uuid

A modern, zero-alloc, zero-dependency Go UUID library implementing RFC 9562. Built for Go 1.26+ with first-class support for V7 timestamp-ordered UUIDs, pooled generation, and batch APIs.

go get github.com/pscheid92/uuid

Quick Start

import "github.com/pscheid92/uuid"

id := uuid.NewV4()                                       // random UUID
id  = uuid.NewV7()                                       // timestamp-ordered, database-friendly
id, err := uuid.Parse("550e8400-e29b-41d4-a716-446655440000") // parse a string
fmt.Println(id.String())                                  // "550e8400-e29b-41d4-a716-446655440000"

Supported Versions

Version Description Function
V3 Deterministic (MD5) NewV3(namespace, name)
V4 Random NewV4() / Pool.NewV4() / NewV4Batch(n)
V5 Deterministic (SHA-1) NewV5(namespace, name)
V7 Timestamp + random NewV7() / Pool.NewV7() / Generator.NewV7Batch(n)
V8 Custom data NewV8(data)

Usage

Generation
// Random (V4) - most common
id := uuid.NewV4()

// Timestamp-ordered (V7) - recommended for new systems, database-friendly
id := uuid.NewV7()

// Deterministic (V5, SHA-1) - same inputs always produce the same UUID
id := uuid.NewV5(uuid.NamespaceDNS, "www.example.com")
// 2ed6657d-e927-568b-95e1-2665a8aea6a2

// Deterministic (V3, MD5) - prefer V5 over V3
id := uuid.NewV3(uuid.NamespaceDNS, "www.example.com")
// 5df41881-3aed-3515-88a7-2f4a814cf09e
Parsing & Formatting

Parse is strict - it only accepts the standard 36-character hyphenated form:

id, err := uuid.Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8")

ParseLenient additionally accepts URN, braced, and compact forms:

id, _ := uuid.ParseLenient("urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8")
id, _ := uuid.ParseLenient("{6ba7b810-9dad-11d1-80b4-00c04fd430c8}")
id, _ := uuid.ParseLenient("6ba7b8109dad11d180b400c04fd430c8")

MustParse panics on failure, useful for package-level constants:

var myID = uuid.MustParse("550e8400-e29b-41d4-a716-446655440000")

Format back to strings:

id.String() // "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
id.URN()    // "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
Serialization

UUID implements encoding.TextMarshaler/TextUnmarshaler (JSON), database/sql.Scanner, and driver.Valuer (SQL). Use a *UUID pointer for nullable fields:

type User struct {
    ID       uuid.UUID  `json:"id"`
    ParentID *uuid.UUID `json:"parent_id"` // null in JSON, SQL NULL when nil
}

// JSON: {"id":"550e8400-e29b-41d4-a716-446655440000","parent_id":null}

var id uuid.UUID
err := row.Scan(&id)

UUIDs are sortable via uuid.Compare:

slices.SortFunc(ids, uuid.Compare)

Why This Library?

Go already has google/uuid and gofrs/uuid. Here's what this one does differently:

  • Zero allocations: NewV4, NewV7, Parse, MarshalText, and UnmarshalText all allocate nothing. Other libraries allocate at least once per call.
  • High-throughput APIs: Pool (~14x faster V4, ~2x faster V7) and Batch (~25x faster bulk V4) amortize crypto/rand cost. No equivalent exists in other libraries.
  • V7 monotonicity built-in: Sub-millisecond ordering via RFC 9562 Method 3, with automatic counter fallback. No configuration needed.
  • No global mutable state: No SetRand, no global clock. V3/V4/V5/V8 are pure functions. V7 monotonicity is scoped to a Generator instance.
  • Strict by default: Parse accepts only xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. Use ParseLenient when you explicitly want URN, braced, or compact forms.
  • Simple value type: UUID is [16]byte: comparable, copyable, safe as map key. No NullUUID - use *UUID for nullable SQL/JSON fields.
  • Modern Go, zero dependencies: Targets Go 1.26+, uses crypto/rand (infallible), encoding.TextAppender, hash.Cloner. Only stdlib. No legacy baggage, no V1/V2/V6.

Further Reading

  • Advanced Usage: V7 monotonicity, high-throughput Pool and Batch APIs, properties, namespace constants.
  • Internals: V7 bit layout, sub-millisecond precision, monotonic counter fallback, Pool amortization, hash.Cloner optimization, parse lookup table.

Benchmarks

All generation and formatting hot paths are zero-alloc. Compared to google/uuid and gofrs/uuid on Apple M2:

Benchmark pscheid92/uuid google/uuid gofrs/uuid
NewV4 247 ns 291 ns 274 ns
NewV4 (Pool) 17 ns - -
NewV4Batch(100) 1,025 ns 25,483 ns 24,768 ns
NewV7 106 ns 309 ns 130 ns
NewV7 (Pool) 50 ns - -
NewV7Batch(100) 800 ns 30,285 ns 12,410 ns
Parse 23 ns 21 ns 27 ns
MarshalText 11 ns 18 ns 27 ns

All entries for this library are zero-alloc; other libraries allocate 1 per operation (generation) or 1 per call (formatting). Run the comparison benchmarks yourself:

cd bench && go test -bench=. -benchmem ./...

License

MIT License. See LICENSE for details.

Documentation

Overview

Package uuid implements UUID generation and parsing per RFC 9562.

Supported versions:

  • V3 (MD5 name-based): deterministic, canonical IDs
  • V4 (Random): most common
  • V5 (SHA-1 name-based): deterministic, preferred over V3
  • V7 (Unix timestamp + random): recommended for new systems
  • V8 (Custom/experimental): user-provided data with version+variant bits

UUID is a 16-byte value type that is comparable and safe for use as a map key. The zero value is the Nil UUID (all zeros).

Generation

Stateless functions require no configuration:

id := uuid.NewV4()                              // random
id := uuid.NewV3(uuid.NamespaceDNS, "example")  // deterministic (MD5)
id := uuid.NewV5(uuid.NamespaceDNS, "example")  // deterministic (SHA-1)

For V7 UUIDs with per-instance monotonicity, use a Generator:

gen := uuid.NewGenerator()
id := gen.NewV7()

A package-level convenience function is also available:

id := uuid.NewV7()

Parsing

Parse is strict: it only accepts the standard 36-character hyphenated form. ParseLenient additionally accepts URN, braced, and compact (32-hex) forms.

id, err := uuid.Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
id, err := uuid.ParseLenient("urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8")

SQL NULL handling

Instead of a separate NullUUID type, use a *UUID pointer:

var id *uuid.UUID  // nil = SQL NULL

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	NamespaceDNS  = UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
	NamespaceURL  = UUID{0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
	NamespaceOID  = UUID{0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
	NamespaceX500 = UUID{0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
)

RFC 9562 Appendix C pre-defined namespace UUIDs.

View Source
var Max = UUID{
	0xff, 0xff, 0xff, 0xff,
	0xff, 0xff, 0xff, 0xff,
	0xff, 0xff, 0xff, 0xff,
	0xff, 0xff, 0xff, 0xff,
}

Max is the maximum UUID (all 0xFF bytes), defined in RFC 9562 Section 5.10.

Functions

func Compare

func Compare(a, b UUID) int

Compare returns an integer comparing two UUIDs lexicographically. The result is 0 if a == b, -1 if a < b, and +1 if a > b. This is suitable for use with slices.SortFunc.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/pscheid92/uuid"
)

func main() {
	ids := []uuid.UUID{
		uuid.MustParse("00000000-0000-0000-0000-000000000003"),
		uuid.MustParse("00000000-0000-0000-0000-000000000001"),
		uuid.MustParse("00000000-0000-0000-0000-000000000002"),
	}
	slices.SortFunc(ids, uuid.Compare)
	for _, id := range ids {
		fmt.Println(id)
	}
}
Output:

00000000-0000-0000-0000-000000000001
00000000-0000-0000-0000-000000000002
00000000-0000-0000-0000-000000000003

Types

type Generator

type Generator struct {
	// contains filtered or unexported fields
}

Generator produces Version 7 UUIDs with per-instance monotonicity. Multiple goroutines may safely call NewV7 concurrently on the same Generator.

Example
package main

import (
	"fmt"

	"github.com/pscheid92/uuid"
)

func main() {
	gen := uuid.NewGenerator()
	id := gen.NewV7()
	fmt.Println(id.Version())
}
Output:

V7

func NewGenerator

func NewGenerator() *Generator

NewGenerator returns a new V7 UUID generator with its own monotonicity state.

func (*Generator) NewV7

func (g *Generator) NewV7() UUID

NewV7 returns a new Version 7 UUID.

The UUID encodes a 48-bit Unix millisecond timestamp in bits 0–47 and 12 bits of sub-millisecond precision in the rand_a field (bits 48–59), computed per RFC 9562 Section 6.2 Method 3. The rand_b field (bytes 8–15, bits 64–127) is filled with random data from crypto/rand.

When multiple UUIDs are generated faster than the clock resolution, the combined timestamp+seq counter is incremented to guarantee monotonicity within this Generator.

func (*Generator) NewV7Batch

func (g *Generator) NewV7Batch(n int) []UUID

NewV7Batch returns n Version 7 UUIDs that are monotonically increasing. It amortizes the cost of crypto/rand and time.Now by performing a single call of each, making it significantly faster than calling Generator.NewV7 in a loop.

Example
package main

import (
	"fmt"

	"github.com/pscheid92/uuid"
)

func main() {
	gen := uuid.NewGenerator()
	ids := gen.NewV7Batch(3)
	fmt.Println(len(ids))
	fmt.Println(ids[0].Version())
}
Output:

3
V7

type LengthError

type LengthError struct {
	Got  int    // the actual length
	Want string // description of expected length
}

LengthError is returned when the input has an unexpected byte length.

Use errors.AsType to check for this error:

if lerr, ok := errors.AsType[*LengthError](err); ok {
    fmt.Println(lerr.Got, lerr.Want)
}

func (*LengthError) Error

func (e *LengthError) Error() string

type ParseError

type ParseError struct {
	Input string // the string that failed to parse
	Msg   string // description of the problem
}

ParseError is returned when a UUID string cannot be parsed.

Use errors.AsType to check for this error:

if perr, ok := errors.AsType[*ParseError](err); ok {
    fmt.Println(perr.Input)
}

func (*ParseError) Error

func (e *ParseError) Error() string

type Pool

type Pool struct {
	// contains filtered or unexported fields
}

Pool amortizes the cost of crypto/rand by pre-generating random bytes in bulk. It provides high-throughput Pool.NewV4 and Pool.NewV7 methods that are functionally equivalent to the package-level functions. Multiple goroutines may safely call methods concurrently.

func NewPool

func NewPool() *Pool

NewPool returns a new Pool that amortizes crypto/rand overhead.

func (*Pool) NewV4

func (p *Pool) NewV4() UUID

NewV4 returns a new random (Version 4) UUID from the pool. It is functionally equivalent to the package-level NewV4 but amortizes the crypto/rand overhead across pool refills.

Example
package main

import (
	"fmt"

	"github.com/pscheid92/uuid"
)

func main() {
	pool := uuid.NewPool()
	id := pool.NewV4()
	fmt.Println(id.Version())
}
Output:

V4

func (*Pool) NewV7

func (p *Pool) NewV7() UUID

NewV7 returns a new Version 7 UUID from the pool. It is functionally equivalent to Generator.NewV7 but amortizes the crypto/rand overhead by buffering random bytes for the rand_b field. Timestamps are computed live to remain accurate.

Example
package main

import (
	"fmt"

	"github.com/pscheid92/uuid"
)

func main() {
	pool := uuid.NewPool()
	id := pool.NewV7()
	fmt.Println(id.Version())
}
Output:

V7

type UUID

type UUID [16]byte

UUID is a 128-bit universally unique identifier per RFC 9562. It is a value type: comparable, copyable, and safe for use as a map key.

var Nil UUID

Nil is the zero-value UUID (all zeros).

func FromBytes

func FromBytes(b []byte) (UUID, error)

FromBytes creates a UUID from a 16-byte slice.

Example
package main

import (
	"fmt"

	"github.com/pscheid92/uuid"
)

func main() {
	b := []byte{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}
	id, err := uuid.FromBytes(b)
	if err != nil {
		panic(err)
	}
	fmt.Println(id)
}
Output:

6ba7b810-9dad-11d1-80b4-00c04fd430c8

func MustParse

func MustParse(s string) UUID

MustParse is like Parse but panics if the string cannot be parsed. It simplifies initialization of global variables holding UUIDs.

func NewV3

func NewV3(namespace UUID, name string) UUID

NewV3 returns a deterministic Version 3 (MD5) UUID for the given namespace and name.

Example
package main

import (
	"fmt"

	"github.com/pscheid92/uuid"
)

func main() {
	id := uuid.NewV3(uuid.NamespaceDNS, "www.example.com")
	fmt.Println(id)
}
Output:

5df41881-3aed-3515-88a7-2f4a814cf09e

func NewV4

func NewV4() UUID

NewV4 returns a new random (Version 4) UUID. It reads from crypto/rand which cannot fail on Go 1.26+.

Example
package main

import (
	"fmt"

	"github.com/pscheid92/uuid"
)

func main() {
	id := uuid.NewV4()
	fmt.Println(id.Version())
}
Output:

V4

func NewV4Batch

func NewV4Batch(n int) []UUID

NewV4Batch returns n random (Version 4) UUIDs. It amortizes the cost of crypto/rand by reading all random bytes in a single call, making it significantly faster than calling NewV4 in a loop.

Example
package main

import (
	"fmt"

	"github.com/pscheid92/uuid"
)

func main() {
	ids := uuid.NewV4Batch(3)
	fmt.Println(len(ids))
	fmt.Println(ids[0].Version())
}
Output:

3
V4

func NewV5

func NewV5(namespace UUID, name string) UUID

NewV5 returns a deterministic Version 5 (SHA-1) UUID for the given namespace and name.

Example
package main

import (
	"fmt"

	"github.com/pscheid92/uuid"
)

func main() {
	id := uuid.NewV5(uuid.NamespaceDNS, "www.example.com")
	fmt.Println(id)
}
Output:

2ed6657d-e927-568b-95e1-2665a8aea6a2

func NewV7

func NewV7() UUID

NewV7 returns a new Version 7 (Unix timestamp + random) UUID using the package-level default generator. For isolated monotonicity guarantees, create a dedicated Generator with NewGenerator.

Example
package main

import (
	"fmt"

	"github.com/pscheid92/uuid"
)

func main() {
	id := uuid.NewV7()
	fmt.Println(id.Version())
}
Output:

V7

func NewV8

func NewV8(data [16]byte) UUID

NewV8 returns a Version 8 UUID constructed from user-provided data. The version and variant bits are set; all other 122 bits come from data. Uniqueness is the caller's responsibility per RFC 9562 Section 5.8.

Example
package main

import (
	"fmt"

	"github.com/pscheid92/uuid"
)

func main() {
	var data [16]byte
	copy(data[:], "custom-data-here")
	id := uuid.NewV8(data)
	fmt.Println(id.Version())
}
Output:

V8

func Parse

func Parse(s string) (UUID, error)

Parse parses a UUID from the standard 36-character hyphenated form: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.

For URN, braced, or compact (32-hex) forms, use ParseLenient.

Example
package main

import (
	"fmt"

	"github.com/pscheid92/uuid"
)

func main() {
	id, err := uuid.Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
	if err != nil {
		panic(err)
	}
	fmt.Println(id)
}
Output:

6ba7b810-9dad-11d1-80b4-00c04fd430c8

func ParseLenient

func ParseLenient(s string) (UUID, error)

ParseLenient parses a UUID from any of these forms:

  • Standard: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx (36 chars)
  • URN: urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx (45 chars)
  • Braced: {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} (38 chars)
  • Compact: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx (32 chars)
Example
package main

import (
	"fmt"

	"github.com/pscheid92/uuid"
)

func main() {
	// Accepts URN, braced, and compact forms in addition to standard
	id, err := uuid.ParseLenient("urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8")
	if err != nil {
		panic(err)
	}
	fmt.Println(id)
}
Output:

6ba7b810-9dad-11d1-80b4-00c04fd430c8

func (UUID) AppendBinary

func (u UUID) AppendBinary(b []byte) ([]byte, error)

AppendBinary appends the raw 16-byte representation of u to b. It implements encoding.BinaryAppender.

func (UUID) AppendText

func (u UUID) AppendText(b []byte) ([]byte, error)

AppendText appends the textual (36-char hyphenated) representation of u to b. It implements encoding.TextAppender.

func (UUID) Bytes

func (u UUID) Bytes() []byte

Bytes returns a copy of the UUID as a 16-byte slice.

func (UUID) IsNil

func (u UUID) IsNil() bool

IsNil reports whether u is the zero-value (Nil) UUID.

func (UUID) MarshalBinary

func (u UUID) MarshalBinary() ([]byte, error)

MarshalBinary returns the raw 16-byte representation. It implements encoding.BinaryMarshaler.

func (UUID) MarshalText

func (u UUID) MarshalText() ([]byte, error)

MarshalText returns the 36-character hyphenated representation. It implements encoding.TextMarshaler. JSON encoding uses this method automatically.

func (*UUID) Scan

func (u *UUID) Scan(src any) error

Scan implements database/sql.Scanner. It supports scanning from:

For SQL NULL handling, use *UUID (nil pointer = NULL).

func (UUID) String

func (u UUID) String() string

String returns the standard 36-character hyphenated UUID representation: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.

func (UUID) Time

func (u UUID) Time() time.Time

Time extracts the millisecond-precision Unix timestamp from a V7 UUID. For non-V7 UUIDs, the returned time is meaningless.

func (UUID) URN

func (u UUID) URN() string

URN returns the UUID in URN form: urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.

Example
package main

import (
	"fmt"

	"github.com/pscheid92/uuid"
)

func main() {
	id := uuid.MustParse("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
	fmt.Println(id.URN())
}
Output:

urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8

func (*UUID) UnmarshalBinary

func (u *UUID) UnmarshalBinary(data []byte) error

UnmarshalBinary sets u from a 16-byte slice. It implements encoding.BinaryUnmarshaler.

func (*UUID) UnmarshalText

func (u *UUID) UnmarshalText(data []byte) error

UnmarshalText parses a UUID from text (strict 36-char format). It implements encoding.TextUnmarshaler.

func (UUID) Value

func (u UUID) Value() (driver.Value, error)

Value implements database/sql/driver.Valuer. It returns the UUID as a 36-character string.

func (UUID) Variant

func (u UUID) Variant() Variant

Variant returns the UUID variant (bits 64–65).

func (UUID) Version

func (u UUID) Version() Version

Version returns the UUID version (bits 48–51).

type Variant

type Variant uint8

Variant represents the UUID variant field.

const (
	VariantNCS       Variant = 0 // NCS backward compatibility
	VariantRFC9562   Variant = 1 // RFC 9562 (formerly RFC 4122)
	VariantMicrosoft Variant = 2 // Microsoft backward compatibility
	VariantFuture    Variant = 3 // Reserved for future definition
)

UUID variant constants.

func (Variant) String

func (v Variant) String() string

String returns the variant name.

type Version

type Version uint8

Version represents the UUID version field.

const (
	VNil Version = 0
	V3   Version = 3
	V4   Version = 4
	V5   Version = 5
	V7   Version = 7
	V8   Version = 8
	VMax Version = 15
)

UUID version constants.

func (Version) String

func (v Version) String() string

String returns the version name.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL