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 ¶
- Variables
- func Compare(a, b UUID) int
- type Generator
- type LengthError
- type ParseError
- type Pool
- type UUID
- func FromBytes(b []byte) (UUID, error)
- func MustParse(s string) UUID
- func NewV4() UUID
- func NewV4Batch(n int) []UUID
- func NewV5(namespace UUID, name string) UUID
- func NewV7() UUID
- func NewV7At(t time.Time) UUID
- func NewV7Batch(n int) []UUID
- func NewV8(data [16]byte) UUID
- func Parse(s string) (UUID, error)
- func ParseLenient(s string) (UUID, error)
- func (u UUID) AppendBinary(b []byte) ([]byte, error)
- func (u UUID) AppendText(b []byte) ([]byte, error)
- func (u UUID) Bytes() []byte
- func (u UUID) Compare(v UUID) int
- func (u UUID) IsNil() bool
- func (u UUID) MarshalBinary() ([]byte, error)
- func (u UUID) MarshalText() ([]byte, error)
- func (u *UUID) Scan(src any) error
- func (u UUID) String() string
- func (u UUID) Time() (time.Time, bool)
- func (u UUID) URN() string
- func (u *UUID) UnmarshalBinary(data []byte) error
- func (u *UUID) UnmarshalText(data []byte) error
- func (u UUID) Value() (driver.Value, error)
- func (u UUID) Variant() Variant
- func (u UUID) Version() Version
- type Variant
- type Version
Examples ¶
Constants ¶
This section is empty.
Variables ¶
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.
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 ¶
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 ¶
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 ¶
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 (*Pool) NewV4 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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
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
NewV7Batch returns n monotonically increasing Version 7 UUIDs using the package-level default generator. See Generator.NewV7Batch.
func NewV8 ¶
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 ¶
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 ¶
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 ¶
AppendBinary appends the raw 16-byte representation of u to b. It implements encoding.BinaryAppender.
func (UUID) AppendText ¶
AppendText appends the textual (36-char hyphenated) representation of u to b. It implements encoding.TextAppender.
func (UUID) Compare ¶ added in v0.6.0
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) MarshalBinary ¶
MarshalBinary returns the raw 16-byte representation. It implements encoding.BinaryMarshaler.
func (UUID) MarshalText ¶
MarshalText returns the 36-character hyphenated representation. It implements encoding.TextMarshaler. JSON encoding uses this method automatically.
func (*UUID) Scan ¶
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 ¶
String returns the standard 36-character hyphenated UUID representation: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
func (UUID) Time ¶
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 ¶
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 ¶
UnmarshalBinary sets u from a 16-byte slice, as FromBytes does. It implements encoding.BinaryUnmarshaler. On error, u is left unchanged.
func (*UUID) UnmarshalText ¶
UnmarshalText parses a UUID from text (strict 36-char format). It implements encoding.TextUnmarshaler. On error, u is left unchanged.
func (UUID) Value ¶
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
type Variant ¶
type Variant uint8
Variant represents the UUID variant field.