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
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)
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)
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
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
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
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
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)
go get github.com/google/uuidRequires 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.