Installation
Install the Google UUID package:
Terminal
go get github.com/google/uuid
Quick Start - Generate UUID v4
The simplest way to generate a random UUID:
main.go
package main
import (
"fmt"
"github.com/google/uuid"
)
func main() {
// Generate UUID v4 (random)
id := uuid.New()
fmt.Println(id)
// Output: 550e8400-e29b-41d4-a716-446655440000
// Or use uuid.NewString() for string directly
idStr := uuid.NewString()
fmt.Println(idStr)
// Generate multiple UUIDs
for i := 0; i < 5; i++ {
fmt.Println(uuid.New())
}
}
All UUID Versions
Generate different UUID versions:
Go
package main
import (
"fmt"
"github.com/google/uuid"
)
func main() {
// UUID v4 - Random (most common)
v4 := uuid.New()
fmt.Printf("v4: %s\n", v4)
// Or explicit v4
v4Random, err := uuid.NewRandom()
if err != nil {
panic(err)
}
fmt.Printf("v4 (explicit): %s\n", v4Random)
// UUID v1 - Timestamp + MAC
v1, err := uuid.NewUUID()
if err != nil {
panic(err)
}
fmt.Printf("v1: %s\n", v1)
// UUID v7 - Unix timestamp (sortable) - requires v1.6+
v7, err := uuid.NewV7()
if err != nil {
panic(err)
}
fmt.Printf("v7: %s\n", v7)
// UUID v6 - Reordered timestamp
v6, err := uuid.NewV6()
if err != nil {
panic(err)
}
fmt.Printf("v6: %s\n", v6)
// UUID v5 - SHA-1 hash (deterministic)
v5 := uuid.NewSHA1(uuid.NameSpaceDNS, []byte("example.com"))
fmt.Printf("v5: %s\n", v5)
// UUID v3 - MD5 hash (deterministic)
v3 := uuid.NewMD5(uuid.NameSpaceDNS, []byte("example.com"))
fmt.Printf("v3: %s\n", v3)
}
Parse & Validate UUID
Parse UUID strings and validate format:
Go
package main
import (
"fmt"
"log"
"github.com/google/uuid"
)
func main() {
// Parse from string
id, err := uuid.Parse("550e8400-e29b-41d4-a716-446655440000")
if err != nil {
log.Fatal("Invalid UUID:", err)
}
fmt.Println("Parsed UUID:", id)
// MustParse (panics if invalid)
id2 := uuid.MustParse("550e8400-e29b-41d4-a716-446655440000")
// Validate without parsing
func isValidUUID(s string) bool {
_, err := uuid.Parse(s)
return err == nil
}
fmt.Println(isValidUUID("550e8400-e29b-41d4-a716-446655440000")) // true
fmt.Println(isValidUUID("not-a-uuid")) // false
// Get version
fmt.Println("Version:", id.Version()) // 4
// Get variant
fmt.Println("Variant:", id.Variant()) // RFC4122
// Nil UUID
var nilUUID uuid.UUID // Zero value is Nil
fmt.Println(nilUUID == uuid.Nil) // true
// Check if nil
if id == uuid.Nil {
fmt.Println("UUID is nil")
}
}
UUID with GORM (Database)
Use UUIDs with GORM ORM for PostgreSQL/MySQL:
Go - GORM
package main
import (
"github.com/google/uuid"
"gorm.io/gorm"
"gorm.io/driver/postgres"
"time"
)
type User struct {
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()"`
Name string `gorm:"not null"`
Email string `gorm:"uniqueIndex;not null"`
CreatedAt time.Time
UpdatedAt time.Time
}
// Hook to generate UUID before create
func (u *User) BeforeCreate(tx *gorm.DB) error {
if u.ID == uuid.Nil {
u.ID = uuid.New()
}
return nil
}
func main() {
dsn := "host=localhost user=postgres password=secret dbname=mydb port=5432"
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
panic(err)
}
// Auto-migrate
db.AutoMigrate(&User{})
// Create user
user := User{
Name: "John Doe",
Email: "john@example.com",
}
result := db.Create(&user)
if result.Error != nil {
panic(result.Error)
}
fmt.Printf("Created user with ID: %s\n", user.ID)
// Query by UUID
var foundUser User
db.Where("id = ?", user.ID).First(&foundUser)
fmt.Printf("Found: %s\n", foundUser.Name)
// Query with string UUID
uuidStr := "550e8400-e29b-41d4-a716-446655440000"
parsedUUID, _ := uuid.Parse(uuidStr)
db.Where("id = ?", parsedUUID).First(&foundUser)
}
UUID in HTTP API (Gin Framework)
Use UUIDs in REST API endpoints:
Go - Gin
package main
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
type CreateUserRequest struct {
Name string `json:"name" binding:"required"`
Email string `json:"email" binding:"required,email"`
}
type UserResponse struct {
ID uuid.UUID `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
func main() {
r := gin.Default()
// GET user by UUID
r.GET("/users/:id", func(c *gin.Context) {
idStr := c.Param("id")
// Parse UUID
id, err := uuid.Parse(idStr)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": "Invalid UUID format",
})
return
}
// Fetch user (mock)
user := UserResponse{
ID: id,
Name: "John Doe",
Email: "john@example.com",
}
c.JSON(http.StatusOK, user)
})
// POST create user
r.POST("/users", func(c *gin.Context) {
var req CreateUserRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
// Create user with new UUID
user := UserResponse{
ID: uuid.New(),
Name: req.Name,
Email: req.Email,
}
c.JSON(http.StatusCreated, user)
})
r.Run(":8080")
}
Extract Timestamp from UUID v7
Get the timestamp embedded in UUID v7:
Go
package main
import (
"fmt"
"time"
"github.com/google/uuid"
)
func main() {
// Generate UUID v7
v7, _ := uuid.NewV7()
fmt.Printf("UUID v7: %s\n", v7)
// Get timestamp from v7 UUID
timestamp, ok := v7.Time()
if ok {
fmt.Printf("Timestamp: %s\n", timestamp)
fmt.Printf("Unix: %d\n", timestamp.Unix())
}
// Create multiple v7 UUIDs (sortable by time)
var uuids []uuid.UUID
for i := 0; i < 5; i++ {
v7, _ := uuid.NewV7()
uuids = append(uuids, v7)
time.Sleep(10 * time.Millisecond)
}
// They're naturally sorted by creation time
for _, id := range uuids {
ts, _ := id.Time()
fmt.Printf("%s - %s\n", id, ts)
}
}
UUID to/from Bytes
Go
package main
import (
"encoding/base64"
"encoding/hex"
"fmt"
"github.com/google/uuid"
)
func main() {
id := uuid.New()
// UUID is already [16]byte internally
bytes := id[:]
fmt.Printf("Bytes: %v\n", bytes)
fmt.Printf("Length: %d\n", len(bytes)) // 16
// From bytes
var byteArray [16]byte
copy(byteArray[:], bytes)
fromBytes, err := uuid.FromBytes(bytes)
if err != nil {
panic(err)
}
fmt.Printf("From bytes: %s\n", fromBytes)
// To hex string
hexStr := hex.EncodeToString(bytes)
fmt.Printf("Hex: %s\n", hexStr)
// To Base64 (compact representation)
base64Str := base64.StdEncoding.EncodeToString(bytes)
fmt.Printf("Base64: %s\n", base64Str)
// String representations
fmt.Printf("String: %s\n", id.String())
fmt.Printf("URN: %s\n", id.URN())
}
Custom Types with UUID
Create type-safe UUID wrappers:
Go
package main
import (
"database/sql/driver"
"fmt"
"github.com/google/uuid"
)
// Type-safe UserID
type UserID uuid.UUID
func NewUserID() UserID {
return UserID(uuid.New())
}
func (u UserID) String() string {
return uuid.UUID(u).String()
}
func (u UserID) MarshalJSON() ([]byte, error) {
return []byte(`"` + u.String() + `"`), nil
}
func (u *UserID) UnmarshalJSON(data []byte) error {
str := string(data[1 : len(data)-1])
id, err := uuid.Parse(str)
if err != nil {
return err
}
*u = UserID(id)
return nil
}
// GORM/SQL Scanner interface
func (u *UserID) Scan(value interface{}) error {
var id uuid.UUID
if err := id.Scan(value); err != nil {
return err
}
*u = UserID(id)
return nil
}
func (u UserID) Value() (driver.Value, error) {
return uuid.UUID(u).Value()
}
// Usage
type User struct {
ID UserID
Name string
}
func main() {
user := User{
ID: NewUserID(),
Name: "Alice",
}
fmt.Printf("User ID: %s\n", user.ID)
}
Standard Library database/sql
Use UUIDs with standard database/sql:
Go - database/sql
package main
import (
"database/sql"
"fmt"
"log"
"github.com/google/uuid"
_ "github.com/lib/pq" // PostgreSQL driver
)
func main() {
db, err := sql.Open("postgres",
"host=localhost user=postgres password=secret dbname=mydb")
if err != nil {
log.Fatal(err)
}
defer db.Close()
// Insert with UUID
id := uuid.New()
_, err = db.Exec(
"INSERT INTO users (id, name, email) VALUES ($1, $2, $3)",
id, "Bob Wilson", "bob@example.com",
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Inserted user with ID: %s\n", id)
// Query by UUID
var name string
var email string
var queriedID uuid.UUID
err = db.QueryRow(
"SELECT id, name, email FROM users WHERE id = $1",
id,
).Scan(&queriedID, &name, &email)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Found: %s (%s) - %s\n", name, email, queriedID)
}