uuid

package module
v0.6.0 Latest Latest
Warning

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

Go to latest
Published: Sep 22, 2026 License: MIT Imports: 14 Imported by: 0

README

CI Go Reference Go Report Card

uuid

A modern, zero-dependency Go UUID library with zero-alloc hot paths, implementing RFC 9562. Built for Go 1.27+ 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
V4 Random NewV4() / Pool.NewV4() / NewV4Batch(n)
V5 Deterministic (SHA-1) NewV5(namespace, name)
V7 Timestamp + random NewV7() / NewV7At(t) / Pool.NewV7() / 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()

// Timestamp-ordered at a given time (V7) - backfill existing rows so they sort correctly
id := uuid.NewV7At(row.CreatedAt)

// Deterministic (V5, SHA-1) - same inputs always produce the same UUID
id := uuid.NewV5(uuid.NamespaceDNS, "www.example.com")
// 2ed6657d-e927-568b-95e1-2665a8aea6a2
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 (or the Compare method, as in the standard library):

slices.SortFunc(ids, uuid.Compare)
Standard Library Interop

Go 1.27 added a uuid package to the standard library. Both it and this package define UUID as [16]byte, so values convert in either direction at zero cost:

import stdlib "uuid"

id := uuid.UUID(stdlib.New())      // stdlib -> this package
std := stdlib.UUID(uuid.NewV7())   // this package -> stdlib

Use the conversion at API boundaries where a dependency hands you a standard library UUID, and keep this package's type internally for Version, Time, strict parsing, SQL support, and the generation APIs the standard library leaves out.

Why This Library?

Go 1.27 ships a standard library uuid package, and google/uuid and gofrs/uuid have been around for years. The standard library covers V4, V7, lenient parsing, and text encoding with the same [16]byte type as this package, so it is the right choice when that is all you need. This library is for when it is not:

  • Everything the standard library leaves out: V5 and V8, Version/Variant/Time accessors, strict Parse, typed ParseError with the offending input, binary marshaling, database/sql Scan/Value, per-instance Generator monotonicity, NewV7At for backfilling, and the Pool and Batch high-throughput paths. Convert between the two types for free (see Standard Library Interop).

  • Zero allocations: NewV4, NewV5 (names up to 240 bytes), NewV7, Parse, UnmarshalText, and AppendText all allocate nothing. gofrs/uuid allocates on every generation call except NewV5; google/uuid allocates on every one, except V4 and V7 when its pool is enabled.

  • High-throughput APIs: Pool (~14x faster V4, ~2x faster V7) and Batch (~30x faster bulk V4, ~13x bulk V7 at n=100) amortize crypto/rand cost. google/uuid can pool V4 and V7 randomness behind a process-wide toggle (EnableRandPool, not safe to flip while generating), ~1.6–1.8x slower than Pool here; no other library pools or generates in batches.

  • V7 monotonicity built-in: Sub-millisecond ordering via RFC 9562 Method 3, with automatic counter fallback. No configuration needed.

  • No global configuration: No SetRand, no swappable clock or random source. V4/V5/V8 are stateless. V7 monotonicity lives in a Generator: the package-level NewV7 uses a shared default one (like http.DefaultClient), and you can create your own for isolated ordering.

  • 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.27+, uses crypto/rand (infallible), encoding.TextAppender, testing/synctest. Only stdlib. No legacy baggage, no V1/V2/V3/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, zero-alloc V5 hashing, parse lookup table.

Benchmarks

Compared to the Go 1.27 standard library uuid package, google/uuid, and gofrs/uuid on Apple M2 (fastest of 8–12 runs; the fastest entry per row is bold):

Benchmark pscheid92/uuid stdlib (Go 1.27) google/uuid gofrs/uuid
NewV4 240 ns 237 ns 248 ns 243 ns
NewV4 (Pool) 16 ns - 29 ns¹ -
NewV4Batch(100) 752 ns - 24,910 ns² 24,538 ns²
NewV5 63 ns - 100 ns 62 ns
NewV7 104 ns 101 ns 296 ns 117 ns
NewV7 (Pool) 45 ns - 73 ns¹ -
NewV7Batch(100) 778 ns - 29,768 ns² 11,615 ns²
Parse 18 ns 25 ns 19 ns 27 ns
UnmarshalText 18 ns 25 ns 19 ns 27 ns
String 20 ns 29 ns 26 ns 24 ns
MarshalText 17 ns 27 ns 24 ns 21 ns

¹ With google.EnableRandPool(), which also removes the allocation. ² No batch API; the benchmark makes 100 single calls.

All entries for this library and the standard library are zero-alloc except the batches, which allocate their result, and String and MarshalText, which must return a newly allocated result in every library; use AppendText to encode into your own buffer without allocating. Single-call generation is at parity with the standard library and gofrs/uuid (differences of a few ns are run-to-run noise), since all of them read crypto/rand the same way. The text paths take 25–40% less time than the standard library's thanks to lookup-table parsing and an unrolled encoder; google/uuid's parser is within a few percent. google/uuid allocates on every generation call, except V4 and V7 with its pool enabled; gofrs/uuid allocates on every generation call except NewV5. 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:

  • V4 (Random): most common
  • V5 (SHA-1 name-based): deterministic, canonical IDs
  • 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.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. It is equivalent to a.Compare(b) and 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.

The zero value is ready to use; NewGenerator is equivalent to &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. Counter increments can carry into the millisecond field, so under sustained bursts the encoded timestamp (and thus UUID.Time) may run slightly ahead of the wall clock.

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. It returns nil if n <= 0.

All n UUIDs derive from one clock reading: consecutive counter values can carry into the millisecond field, so for large n the encoded timestamps may run slightly ahead of the wall clock.

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, truncated to 64 bytes if longer
	Msg   string // description of the problem; positions are byte offsets into Input
}

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.

Because Pool buffers pre-generated randomness in process memory, it is not fork-safe: a forked process or a cloned/restored VM snapshot can duplicate the buffer, causing both copies to emit identical UUIDs. Use the package-level functions where fork or VM-clone safety matters.

The zero value is ready to use; NewPool is equivalent to &Pool{}.

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, though under sustained bursts they may run slightly ahead of the wall clock (see Generator.NewV7).

Each Pool keeps its own monotonic state, independent of the package-level NewV7 generator and of every other Pool or Generator. UUIDs drawn from different sources are not ordered relative to each other.

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.

Example (StdlibInterop)

Both this package and the standard library uuid package (Go 1.27+) define UUID as [16]byte, so values convert in either direction at zero cost.

package main

import (
	"fmt"

	stdlib "uuid"

	"github.com/pscheid92/uuid"
)

func main() {
	std := stdlib.MustParse("6ba7b810-9dad-11d1-80b4-00c04fd430c8")

	// Standard library -> this package: gain Version, Time, Scan/Value, ...
	id := uuid.UUID(std)
	fmt.Println(id.Version())

	// This package -> standard library.
	back := stdlib.UUID(uuid.NewV5(uuid.NamespaceDNS, "example.com"))
	fmt.Println(back == stdlib.UUID(uuid.NewV5(uuid.NamespaceDNS, "example.com")))
}
Output:
V1
true
var Nil UUID

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

Nil, Max, and the Namespace values are variables only because Go has no array constants. Treat them as read-only: writing to one changes it for every user in the process, including NewV5 callers.

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 NewV4

func NewV4() UUID

NewV4 returns a new random (Version 4) UUID. It reads from crypto/rand, which cannot fail since Go 1.24.

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. It returns nil if n <= 0.

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. It allocates nothing for names up to 240 bytes.

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 NewV7At added in v0.5.0

func NewV7At(t time.Time) UUID

NewV7At returns a Version 7 UUID whose timestamp fields encode t instead of the current time. It is intended for backfilling records that already have a creation time, so their keys sort among live V7 UUIDs at the right position.

The 48-bit millisecond field and the 12-bit sub-millisecond fraction are derived from t exactly as Generator.NewV7 derives them from the clock, so a UUID created "at" an instant sorts where a live UUID created at that instant would. The remaining 62 bits are random from crypto/rand. Two calls with the same t tie on their first 8 bytes and are ordered only by that random tail.

NewV7At is stateless: it neither reads nor advances the monotonic state of any Generator or Pool, so backfilling never pushes live UUIDs ahead of the wall clock.

t must be representable in the 48-bit field, that is between the Unix epoch and roughly the year 10889; NewV7At panics otherwise. A zero time.Time is out of range, which turns an uninitialized field into an immediate panic rather than a silently wrong timestamp.

Example
package main

import (
	"fmt"
	"time"

	"github.com/pscheid92/uuid"
)

func main() {
	// Backfill a record that was created before V7 keys were introduced.
	created := time.Date(2020, time.March, 14, 15, 9, 26, 0, time.UTC)
	id := uuid.NewV7At(created)

	ts, ok := id.Time()
	fmt.Println(id.Version(), ok, ts.UTC())
}
Output:
V7 true 2020-03-14 15:09:26 +0000 UTC

func NewV7Batch added in v0.3.0

func NewV7Batch(n int) []UUID

NewV7Batch returns n monotonically increasing Version 7 UUIDs using the package-level default generator. See Generator.NewV7Batch.

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) Compare added in v0.6.0

func (u UUID) Compare(v UUID) int

Compare returns an integer comparing u and v lexicographically. The result is 0 if u == v, -1 if u < v, and +1 if u > v. It matches the Compare method of the standard library uuid package.

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:

  • string: text form parsed with ParseLenient
  • []byte: 16 raw bytes (a BINARY(16) column), otherwise text form parsed with ParseLenient

A string is always parsed as text, so a 16-character value from a text column is rejected rather than silently read as raw bytes. Drivers deliver binary columns as []byte, which is the only source of raw bytes.

Scanning SQL NULL is an error; use *UUID (nil pointer = NULL) instead. On error, u is left unchanged.

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, bool)

Time extracts the millisecond-precision Unix timestamp from a V7 UUID. The boolean is false, and the time is the zero value, if u is not an RFC 9562 Version 7 UUID; other versions either carry no timestamp or lay it out differently, so decoding them would return a plausible but wrong time. The variant is checked too, because the version field is only defined for VariantRFC9562: a Microsoft GUID whose version bits happen to read 7 carries no timestamp.

For V7 UUIDs generated by this package under sustained bursts, the timestamp may be marginally ahead of the actual creation time due to the monotonic counter (see Generator.NewV7).

Example
package main

import (
	"fmt"
	"time"

	"github.com/pscheid92/uuid"
)

func main() {
	v7 := uuid.NewV7At(time.UnixMilli(1_700_000_000_000))
	v4 := uuid.NewV4()

	_, ok := v7.Time()
	fmt.Println("V7 has a timestamp:", ok)
	_, ok = v4.Time()
	fmt.Println("V4 has a timestamp:", ok)
}
Output:
V7 has a timestamp: true
V4 has a timestamp: false

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, as FromBytes does. It implements encoding.BinaryUnmarshaler. On error, u is left unchanged.

func (*UUID) UnmarshalText

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

UnmarshalText parses a UUID from text (strict 36-char format). It implements encoding.TextUnmarshaler. On error, u is left unchanged.

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, which suits native uuid column types (PostgreSQL, CockroachDB, MariaDB 10.7+) and text columns (SQLite has no UUID type). For BINARY(16) columns, wrap the type and return the raw bytes instead; see the UUID.Value example. UUID.Scan already accepts 16 raw bytes as []byte.

Example
package main

import (
	"database/sql/driver"
	"fmt"

	"github.com/pscheid92/uuid"
)

// BinaryUUID stores the UUID as 16 raw bytes, for BINARY(16) columns
// (MySQL, MariaDB). Scan already accepts 16 raw bytes, so only Value
// needs to be overridden; every other method is promoted from uuid.UUID.
type BinaryUUID struct{ uuid.UUID }

func (b BinaryUUID) Value() (driver.Value, error) {
	return b.Bytes(), nil
}

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

	v, _ := id.Value() // string, for native uuid column types
	fmt.Printf("%T %v\n", v, v)

	bv, _ := BinaryUUID{id}.Value() // []byte, for BINARY(16)
	fmt.Printf("%T %d bytes\n", bv, len(bv.([]byte)))
}
Output:
string 6ba7b810-9dad-11d1-80b4-00c04fd430c8
[]uint8 16 bytes

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
	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. Legacy versions (V1, V2, V3, V6) are named even though this package does not generate them, since Parse accepts UUIDs of any version.

Jump to

Keyboard shortcuts

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