Skip to main content

Searching...

Tools
Articles
View All Results

Developer Lab · Go

Generate UUID in Go

github.com/google/uuid is the Go standard - maintained by Google, backed by crypto/rand (OS CSPRNG). uuid.New() for v4, uuid.NewString() for a string directly, uuid.NewV7() for time-ordered.

Quick Reference

Function Version Sortable Use Case
uuid.New() v4 No General purpose - returns uuid.UUID type
uuid.NewString() v4 No Returns string directly - convenience wrapper
uuid.NewV7() v7 Yes Time-ordered - database PKs, event logs
uuid.Parse() any - Parse and validate - returns error on invalid input

Primary Implementation

Production Ready
go
package main

import (
    "fmt"
    "github.com/google/uuid"
)

func main() {
    // UUID v4 - random, crypto/rand-backed, zero unsafe
    id := uuid.New()
    fmt.Println(id)
    // → f47ac10b-58cc-4372-a567-0e02b2c3d479

    // As a string directly (convenience)
    idStr := uuid.NewString()

    // uuid.UUID is [16]byte - value type, no heap allocation
    var raw [16]byte = id

    // Parse and validate an existing UUID string
    parsed, err := uuid.Parse("f47ac10b-58cc-4372-a567-0e02b2c3d479")
    if err != nil {
        fmt.Printf("Invalid UUID: %v\n", err)
        return
    }
    fmt.Printf("Version: %d\n", parsed.Version()) // → 4

    // Generate multiple
    ids := make([]uuid.UUID, 5)
    for i := range ids {
        ids[i] = uuid.New()
    }
}

All UUID Versions

UUID v4 - Random (recommended default)

go
import "github.com/google/uuid"

// Returns uuid.UUID ([16]byte) - value type, no heap allocation
id := uuid.New()
fmt.Println(id.String()) // → "550e8400-e29b-41d4-a716-446655440000"

// Or get a string directly
idStr := uuid.NewString()

UUID v7 - Time-ordered (database PKs)

go
import "github.com/google/uuid"

// Millisecond-precision timestamp prefix - sorts chronologically
id, err := uuid.NewV7()
if err != nil {
    log.Fatal(err)
}
fmt.Println(id.String()) // → "018e8f6a-1b2c-7d3e-9f4a-5b6c7d8e9f0a"

UUID v5 - Deterministic / Namespace-based

go
import "github.com/google/uuid"

// SHA-1 hash of namespace + name - same inputs always produce the same UUID
id := uuid.NewSHA1(uuid.NameSpaceDNS, []byte("example.com"))
fmt.Println(id.String()) // → always "cfbff0d1-9375-5685-968c-48ce8b15ae17"

Real-World Use Cases

1. gRPC interceptor - request tracing ID

go
import (
    "context"
    "github.com/google/uuid"
    "google.golang.org/grpc"
)

func UnaryRequestIDInterceptor(
    ctx context.Context,
    req interface{},
    info *grpc.UnaryServerInfo,
    handler grpc.UnaryHandler,
) (interface{}, error) {
    requestID := uuid.NewString()
    ctx = context.WithValue(ctx, "requestID", requestID)
    return handler(ctx, req)
}

2. GORM model with UUID primary key

go
import (
    "github.com/google/uuid"
    "gorm.io/gorm"
)

type Order struct {
    ID        uuid.UUID `gorm:"type:uuid;primaryKey"`
    CreatedAt time.Time
    Name      string
}

// Auto-assign UUID before create
func (o *Order) BeforeCreate(tx *gorm.DB) error {
    o.ID = uuid.New()
    return nil
}

3. Distributed tracing - correlation ID

go
import (
    "net/http"
    "github.com/google/uuid"
)

func RequestIDMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        requestID := uuid.NewString()
        w.Header().Set("X-Request-ID", requestID)
        ctx := context.WithValue(r.Context(), "requestID", requestID)
        next.ServeHTTP(w, r.WithContext(ctx))
    })
}

Common Mistakes

Using fmt.Sprintf to build UUID strings

Manually constructing UUID strings with fmt.Sprintf("%x-%x-4%x-...", ...) is error-prone and almost always produces non-compliant UUIDs. Use uuid.New() or uuid.NewString().

Not handling errors from uuid.Parse()

uuid.Parse() returns an error for invalid input. Always check the error - ignoring it means you may silently use a zero-value UUID (00000000-0000-0000-0000-000000000000).

Storing uuid.UUID as a string in structs

uuid.UUID is a [16]byte value type - no heap allocation. Storing it as a string in structs wastes memory and loses type safety. Convert to string only at the boundary.

How It Works

The google/uuid package uses Go's crypto/rand package for entropy, which calls the OS CSPRNG - /dev/urandom on Linux/macOS and CryptGenRandom on Windows.

uuid.UUID is defined as type UUID [16]byte - a value type. Passing it around copies 16 bytes on the stack with zero heap allocation.

Output Formats

id.String()

f47ac10b-58cc-4372-a567-0e02b2c3d479

uuid.NewString()

f47ac10b-58cc-4372-a567-0e02b2c3d479

id[:] - []byte (16 bytes)

[0xf4 0x7a 0xc1 0x0b ...]

Best Practices, Performance, and Security

Best practices

Store uuid.UUID in structs - only call .String() at API/DB boundaries.

Always handle the error from uuid.Parse() - never ignore it.

Use uuid.NewV7() for database PKs - sequential inserts avoid B-tree fragmentation.

Performance

Go generates roughly 5–10 million UUIDs/second. The uuid.UUID type is [16]byte - zero heap allocations when stored in structs.

The .String() call allocates a string. For high-throughput scenarios, use uuid.NewString() which combines generation and formatting in one call.

Security

Entropy source: crypto/rand → OS CSPRNG (/dev/urandom on Linux/macOS, CryptGenRandom on Windows). Cryptographically secure.

Suitable for session tokens, CSRF tokens, and API keys. Never use math/rand for UUID generation.

Installation

UUID v4 (google/uuid)

bash
go get github.com/google/uuid

Requires Go 1.16+. The package is maintained by Google and has no transitive dependencies.

Frequently Asked Questions

How do I generate a UUID in Go?

Go has no UUID type in its standard library. The community standard is the github.com/google/uuid package: run go get github.com/google/uuid, then call uuid.New() for a random v4 UUID or uuid.NewV7() for a time-ordered v7. Both read entropy from crypto/rand.

Is uuid.New() cryptographically secure?

Yes. uuid.New() uses the platform CSPRNG (operating system secure random source), suitable for session tokens, API keys, and idempotency keys. Do not use non-cryptographic random sources for security-sensitive identifiers.

What is the difference between UUID v4 and v7 in Go?

UUID v4 (uuid.New() or equivalent) is fully random and not sortable. UUID v7 embeds a millisecond timestamp for chronological sorting (RFC 9562). Use v4 for general-purpose IDs; use v7 for database primary keys at scale.

Do I need to install a package for UUID generation in Go?

A package or library install may be required. See the Installation section for the recommended approach in Go.

How do I validate a UUID string in Go?

Use the platform's UUID parse/validation function, or test against the RFC 4122 regex: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i. Always validate external input at API boundaries.

Should I use UUIDs as database primary keys in Go applications?

UUIDs work well as primary keys for distributed systems. Prefer native UUID/BINARY(16) column types over VARCHAR(36). For very large tables, consider UUID v7 for better B-tree insert locality.

Can I generate UUIDs in Go without a network connection?

Yes. UUID generation uses local OS entropy sources and does not require network access. Each call is independent and thread-safe on modern platforms.

What output formats are available in Go?

The standard hyphenated lowercase string (36 chars) is the default. Most APIs also support 32-char hex (no hyphens) and 16-byte binary formats. Use string format for APIs and binary for database storage.

What RFC standards apply to Go UUID generation?

Version 4 UUIDs follow RFC 4122. UUID v7 follows RFC 9562 (May 2024). Ensure your chosen method produces compliant version and variant bits.

When should I avoid UUID v1?

Avoid UUID v1 in security-sensitive contexts - it embeds MAC address and timestamp information. Prefer v4 (uuid.New() or equivalent) unless you need legacy Cassandra timeuuid compatibility.

Key definitions

UUID
128-bit universally unique identifier, usually shown as 36 hex characters with hyphens.
CSPRNG
Cryptographically secure pseudo-random number generator - the entropy source behind secure UUID generation.
RFC 4122
IETF standard defining UUID versions 1 through 5. Version 4 is random.
RFC 9562
IETF standard adding UUID versions 6, 7, and 8. Version 7 is time-ordered.