πŸ“š guid - Awesome Go Library for UUID

Go Gopher mascot for guid

Fast cryptographically safe Guid generator for Go (~10x faster than `uuid`)

🏷️ UUID
πŸ“‚ UUID
⭐ 0 stars
View on GitHub πŸ”—

Detailed Description of guid

guid name codecov Mentioned in Awesome Go

Fast cryptographically secure Guid generator for Go.
By Stan Drapkin.

Guid is defined as type Guid [16]byte and filled with 128 cryptographically strong bits.

Go playground

package main

import (
	"fmt"

	"github.com/sdrapkin/guid"
)

func main() {
	for range 4 {
		fmt.Printf("%x\n", guid.New())
	}
	fmt.Println()
	for range 4 {
		g := guid.New()
		fmt.Println(&g) // calls g.String()
	}
}
79c9779af20dcd21fbe60f3b336ed08c
da2026d38edca4371a476efd41333d23
88c3033b002b0e73321509ef26de607f
a84e961ff7f09f5210ea04585f152e73

WF8MvK5CUOrI-enEuvS0jw
AOp8Voi5knpu1mg3RjzmSg
gxOQRIVR4B_uGHD6OP76XA
Zo_hpnDxkOsAWLk1tIS6DA

Why guid? πŸ”₯

guid is a high-performance, cryptographically secure UUID/GUID (Globally Unique Identifier) generator for Go. It's built for speed without compromising on security, offering a significant performance advantageβ€”up to 10x faster than github.com/google/uuid.

Beyond raw speed, guid offers:

  • Cryptographically Strong: Generates 128 cryptographically secure bits for robust, unique identifiers.
  • Optimized for Databases: Includes special GuidPG and GuidSS types that generate sequential Guids, dramatically improving INSERT performance and preventing index fragmentation in PostgreSQL and SQL Server databases.
  • Seamless Interoperability: Easily integrate with existing google/uuid codebases, and even boost uuid's performance by up to 4x using guid.Reader.
  • FIPS 140 Compliant: Ensures adherence to stringent security standards.
  • Zero Allocations for Core Operations: guid.New() generates new Guids with no memory allocations, making it incredibly efficient.

Guid is ~10x faster than github.com/google/uuid πŸ”₯

  • guid.New() is 6~10 ns
  • guid.NewString() is 40~60 ns
  • String() on existing guid is ~40 ns
  • multi-goroutine calls do not increase per-call latency
  • if your library is faster - please let me know!

API Overview

All APIs are safe for concurrent use by multiple goroutines.

FunctionsDescription
guid.New() GuidGenerate a new Guid
guid.NewString() stringGenerate a new Guid as a Base64Url string
guid.NewPG() GuidPGGenerate a new PostgreSQL sequential Guid
guid.NewSS() GuidSSGenerate a new SQL Server sequential Guid
guid.Parse(s string) (Guid, error)Parse a Base64Url string into a Guid
guid.ParseBytes(src []byte) (Guid, error)Parse Base64Url bytes to a Guid
guid.FromBytes(src []byte) (Guid, error)Parse 16-byte slice to a Guid
guid.DecodeBase64URL(dst []byte, src []byte) (ok bool)Decode a Base64Url slice into a Guid slice
guid.Reader πŸ”₯ implements io.ReaderFaster alternative to crypto/rand
guid.NilThe zero-value Guid
Guid methodsDescription
.String() stringEncodes the Guid into Base64Url 22-char string fmt.Stringer
.EncodeBase64URL(dst []byte) errorLike .String() but encodes into len(22) byte slice
.MarshalBinary()Implements encoding.BinaryMarshaler
.UnmarshalBinary()Implements encoding.BinaryUnmarshaler
.MarshalText()Implements encoding.TextMarshaler
.UnmarshalText()Implements encoding.TextUnmarshaler
GuidPG, GuidSS methodsDescription
.Timestamp() time.TimeExtracts the UTC timestamp

Sequential Guids πŸ”₯

guid includes two special types GuidPG and GuidSS optimized for use as database primary keys (PostgreSQL and SQL Server). Their time-ordered composition helps prevent index fragmentation and improves INSERT performance compared to fully random Guids. Note that sequential sorting is only across time.Now() timestamp precision.

  • guid.NewPG(): Generates a GuidPG, which is sortable in PostgreSQL.
    • It is structured as [8-byte timestamp][8 random bytes].
  • guid.NewSS(): Generates a GuidSS, which is sortable in SQL Server.
    • It is structured as [8 random bytes][8-byte SQL Server-ordered timestamp].
  • .Timestamp() on GuidPG/GuidSS returns Guid creation time as UTC time.Time.

Both GuidPG and GuidSS are nearly as fast as guid.New(). They can be used as a standard Guid and support the same interfaces.


Sequential Guid Example:

fmt.Printf("%s\t       %s\t\t\t\t%s\t       %s\n",
	"gpg.String()", "hex(gpg)", "gss.String()", "hex(gss)")
for range 10 {
	gpg := guid.NewPG()
	gss := guid.NewSS()
	fmt.Println(&gpg, hex.EncodeToString(gpg.Guid[:]), &gss, hex.EncodeToString(gss.Guid[:]))
}

gpg := guid.NewPG()
gss := guid.NewSS()
fmt.Println(gpg.Timestamp()) // time.Time
fmt.Println(gss.Timestamp()) // time.Time
gpg.String()           hex(gpg)                         gss.String()           hex(gss)
GFEU88wgQvDlahOowSGTKA 185114f3cc2042f0e56a13a8c1219328 9SurLKL6ti2l0BhRFPPMKA f52bab2ca2fab62da5d0185114f3cc28
GFEU88wopdChlFba89-4yg 185114f3cc28a5d0a19456daf3dfb8ca yTRE6Rr1gISl0BhRFPPMKA c93444e91af58084a5d0185114f3cc28
GFEU88ww9fA01GntVDQ_4w 185114f3cc30f5f034d469ed54343fe3 8SaILyee6q718BhRFPPMMA f126882f279eeaaef5f0185114f3cc30
GFEU88ww9fASNFzZQJpv7Q 185114f3cc30f5f012345cd9409a6fed xZ3KYLzqJ0f18BhRFPPMMA c59dca60bcea2747f5f0185114f3cc30
GFEU88ww9fAHgWvjAmkQJw 185114f3cc30f5f007816be302691027 yEif2kTQBcD18BhRFPPMMA c8489fda44d005c0f5f0185114f3cc30
GFEU88ww9fD4_Vm3PG5Vuw 185114f3cc30f5f0f8fd59b73c6e55bb SRKgSiCc-gL18BhRFPPMMA 4912a04a209cfa02f5f0185114f3cc30
GFEU88ww9fDzO_One7T6BA 185114f3cc30f5f0f33bf3a77bb4fa04 rGr2czgQcmr18BhRFPPMMA ac6af6733810726af5f0185114f3cc30
GFEU88w5PqQAifEi5tqoWQ 185114f3cc393ea40089f122e6daa859 5YYbiI3p7P4-pBhRFPPMOQ e5861b888de9ecfe3ea4185114f3cc39
GFEU88w5PqSFkX4bmxSvMQ 185114f3cc393ea485917e1b9b14af31 PqUPeiyessU-pBhRFPPMOQ 3ea50f7a2c9eb2c53ea4185114f3cc39
GFEU88w5PqTsYX0kcZzL6Q 185114f3cc393ea4ec617d24719ccbe9 yFIlRwKZJNo-pBhRFPPMOQ c8522547029924da3ea4185114f3cc39
2025-07-11 03:32:47.3597457 +0000 UTC
2025-07-11 03:32:47.3597457 +0000 UTC

Interoperability with google/uuid πŸ”₯

  • If you must keep using google/uuid, use guid to increase performance by 2~4x:
// do this before using google/uuid
uuid.SetRand(guid.Reader)
  • Quick conversions between guid and google/uuid if you need uuid behavior:
g := guid.New()
gpg := guid.NewPG()
gss := guid.NewSS()

var u uuid.UUID

u = uuid.UUID(g) // copy by value
fmt.Println(u)

u = uuid.UUID(gpg.Guid) // copy by value
fmt.Println(u)

u = uuid.UUID(gss.Guid) // copy by value
fmt.Println(u)

uptr := (*uuid.UUID)(unsafe.Pointer(&g)) // zero-copy cast
g[0], g[1] = 0xAB, 0xCD
fmt.Println(uptr)
05166521-a124-9d0c-cb11-7f0cbf3a030c
1852e32a-5aac-bb9c-bffc-b330606813af
7e8badae-57f8-c88d-bb9c-1852e32a5aac
abcd6521-a124-9d0c-cb11-7f0cbf3a030c

FIPS Ready

uuid Benchmarks with and without guid.Reader

Benchmark NameTime per OpBytes per OpAllocs per Op
Benchmark_uuid_New_x10-83031 ns/op160 B/op10 allocs/op
Benchmark_uuid_New_guidRand_x10-8 πŸ”₯862.0 ns/op160 B/op10 allocs/op
Benchmark_uuid_New_RandPool_x10-8747.6 ns/op0 B/op0 allocs/op
Benchmark_uuid_New_RandPool_guidRand_x10-8 πŸ”₯516.8 ns/op0 B/op0 allocs/op
Benchmark_uuid_New_Parallel_x10-81230 ns/op160 B/op10 allocs/op
Benchmark_uuid_New_Parallel_guidRand_x10-8 πŸ”₯510.0 ns/op160 B/op10 allocs/op
Benchmark_uuid_New_Parallel_RandPool_x10-81430 ns/op0 B/op0 allocs/op
Benchmark_uuid_New_Parallel_RandPool_guidRand_x10-8 πŸ”₯1185 ns/op0 B/op0 allocs/op

Guid Benchmarks [raw]

go test -bench=.* -benchtime=4s
goos: windows
goarch: amd64
pkg: github.com/sdrapkin/guid
cpu: Intel(R) Core(TM) i7-10510U CPU @ 1.80GHz
Benchmarks guid [10 calls]Time/opBytes/opAllocs/op
guid_New_x10-8203.4 ns/op0 B/op0 allocs/op
guid_NewString_x10-8582.4 ns/op240 B/op10 allocs/op
guid_String_x10-8388.9 ns/op240 B/op10 allocs/op
guid_New_Parallel_x10-8 πŸ”₯62.45 ns/op0 B/op0 allocs/op
guid_NewString_Parallel_x10-8374.2 ns/op240 B/op10 allocs/op

Sequential Guid Benchmarks

guid.NewPG() vs uuid.NewV7() [10 calls]Time/op
guid.NewPG()_x10_Sequential386.4 ns/op
uuid.NewV7()_x10_Sequential887.9 ns/op2.3x slower ⏳
guid.NewPG()_x10_Parallel144.3 ns/op
uuid.NewV7()_x10_Parallel2575 ns/op18x slower ⏳

Alternative library benchmarks:

Benchmarks nanoid v1.35 [10 calls]Time/opBytes/opAllocs/op
guid.NewString() x10 Sequential609.9 ns/op240 B/op10 allocs/op
guid.NewString() x10 Parallel (8 CPU)384.0 ns/op240 B/op10 allocs/op
nanoid.New() x10 Sequential2257 ns/op240 B/op10 allocs/op
nanoid.New() x10 Parallel (8 CPU)1337 ns/op240 B/op10 allocs/op
Benchmarks uuid [10 calls]Time/opBytes/opAllocs/op
uuid_New_x10-82216 ns/op160 B/op10 allocs/op
uuid_New_RandPool_x10-8528.2 ns/op0 B/op0 allocs/op
uuid_New_Parallel_x10-81064 ns/op160 B/op10 allocs/op
uuid_New_RandPool_Parallel_x10-81301 ns/op0 B/op0 allocs/op
Benchmarks [20 guid encodings]Time/opBytes/opAllocs/op
g.String-81025 ns/op480 B/op20 allocs/op
base64.RawURLEncoding.EncodeToString-81867 ns/op960 B/op40 allocs/op
g.EncodeBase64URL-8392.0 ns/op0 B/op0 allocs/op
base64.RawURLEncoding.Encode-8463.4 ns/op0 B/op0 allocs/op

Documentation

Go Reference

Full go doc style documentation: https://pkg.go.dev/github.com/sdrapkin/guid

Requirements

  • Go 1.24+

Installation

Using go get

To install the guid package, run the following command:

go get -u github.com/sdrapkin/guid

To use the guid package in your Go project, import it as follows:

import "github.com/sdrapkin/guid"

JSON Support

Guid supports JSON marshalling and unmarshalling for both value and pointer types:

  • Value fields serialize as 22-character Base64Url strings.
  • Pointer fields serialize as strings or null (for nil pointers).
  • Zero-value Guids (guid.Nil) are handled correctly.

Example: JSON Marshalling

type User struct {
	ID        guid.Guid  `json:"id"`
	ManagerID *guid.Guid `json:"mid"`
}

u, u2 := User{ID: guid.New()}, User{}
data, _ := json.Marshal(u)
fmt.Println(string(data)) // {"id":"tI0EMdDXpOcvvGLktob4Ug","mid":null}

_ = json.Unmarshal(data, &u2)
fmt.Println(u2.ID == u.ID) // true