How to Generate UUID in Rust

Rust uses the uuid crate for generating RFC 4122 compliant UUIDs. This guide covers all UUID versions and common operations.

1. Setup

Add to your Cargo.toml:

[dependencies]
uuid = { version = "1.6", features = ["v4", "v7", "serde"] }

2. Generate UUID v4 (Random)

The most common UUID type, using random data.

use uuid::Uuid;

fn main() {
    // Generate UUID v4
    let uuid = Uuid::new_v4();
    println!("{}", uuid);
    // Output: "550e8400-e29b-41d4-a716-446655440000"
    
    // Generate multiple UUIDs
    for _ in 0..5 {
        println!("{}", Uuid::new_v4());
    }
}

3. Generate UUID v7 (Time-ordered)

UUID v7 is time-sortable and great for database primary keys.

use uuid::Uuid;

fn main() {
    // Generate UUID v7 (requires "v7" feature)
    let uuid = Uuid::now_v7();
    println!("{}", uuid);
    // Output: "018c6e9a-3b4c-7d5e-8f9a-0b1c2d3e4f5a"
    
    // UUIDs generated close together are sortable
    let uuid1 = Uuid::now_v7();
    let uuid2 = Uuid::now_v7();
    println!("uuid1 < uuid2: {}", uuid1 < uuid2);  // Often true
}

4. UUID Validation and Parsing

use uuid::Uuid;

fn main() {
    // Parse UUID from string
    let uuid = Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000")
        .expect("Invalid UUID");
    println!("{}", uuid);
    
    // Safe parsing with Result
    match Uuid::parse_str("not-a-uuid") {
        Ok(uuid) => println!("Valid: {}", uuid),
        Err(e) => println!("Invalid: {}", e),
    }
    
    // Parse without hyphens
    let uuid = Uuid::parse_str("550e8400e29b41d4a716446655440000")
        .expect("Invalid UUID");
    println!("{}", uuid);
    
    // Check if nil UUID
    let nil = Uuid::nil();
    println!("Is nil: {}", nil.is_nil());  // true
}

5. UUID Formatting

use uuid::Uuid;

fn main() {
    let uuid = Uuid::new_v4();
    
    // Standard hyphenated format
    println!("{}", uuid);  // 550e8400-e29b-41d4-a716-446655440000
    
    // Hyphenated lowercase
    println!("{}", uuid.hyphenated());
    
    // Simple (no hyphens)
    println!("{}", uuid.simple());  // 550e8400e29b41d4a716446655440000
    
    // URN format
    println!("{}", uuid.urn());  // urn:uuid:550e8400-e29b-41d4-a716-446655440000
    
    // Braced format
    println!("{}", uuid.braced());  // {550e8400-e29b-41d4-a716-446655440000}
    
    // Uppercase
    let upper = uuid.hyphenated().to_string().to_uppercase();
    println!("{}", upper);
}

6. UUID Properties

use uuid::Uuid;

fn main() {
    let uuid = Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000")
        .unwrap();
    
    // Get version
    println!("Version: {:?}", uuid.get_version());  // Some(Random)
    
    // Get variant
    println!("Variant: {:?}", uuid.get_variant());  // RFC4122
    
    // Get as bytes
    let bytes: &[u8; 16] = uuid.as_bytes();
    println!("Bytes: {:?}", bytes);
    
    // Create from bytes
    let from_bytes = Uuid::from_bytes(*bytes);
    println!("From bytes: {}", from_bytes);
}

7. Serde Serialization

use uuid::Uuid;
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, Debug)]
struct User {
    id: Uuid,
    name: String,
}

fn main() {
    let user = User {
        id: Uuid::new_v4(),
        name: "John".to_string(),
    };
    
    // Serialize to JSON
    let json = serde_json::to_string(&user).unwrap();
    println!("{}", json);
    // {"id":"550e8400-e29b-41d4-a716-446655440000","name":"John"}
    
    // Deserialize from JSON
    let parsed: User = serde_json::from_str(&json).unwrap();
    println!("{:?}", parsed);
}

8. Database Integration (SQLx)

use sqlx::postgres::PgPool;
use uuid::Uuid;

#[derive(sqlx::FromRow)]
struct User {
    id: Uuid,
    name: String,
}

async fn create_user(pool: &PgPool, name: &str) -> Result {
    let id = Uuid::new_v4();
    
    sqlx::query("INSERT INTO users (id, name) VALUES ($1, $2)")
        .bind(id)
        .bind(name)
        .execute(pool)
        .await?;
    
    Ok(id)
}

async fn get_user(pool: &PgPool, id: Uuid) -> Result {
    sqlx::query_as::<_, User>("SELECT id, name FROM users WHERE id = $1")
        .bind(id)
        .fetch_one(pool)
        .await
}

9. UUID v1 (MAC + Time)

// Add to Cargo.toml: uuid = { version = "1.6", features = ["v1"] }
use uuid::{Uuid, timestamp::Timestamp};

fn main() {
    // UUID v1 requires a node ID (usually MAC address)
    let node_id = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab];
    
    // Create timestamp context
    let ts = Timestamp::now(uuid::timestamp::context::NoContext);
    
    // Generate UUID v1
    let uuid = Uuid::new_v1(ts, &node_id);
    println!("{}", uuid);
}

10. Bulk Generation

use uuid::Uuid;

fn main() {
    // Generate vector of UUIDs
    let uuids: Vec = (0..10)
        .map(|_| Uuid::new_v4())
        .collect();
    
    for uuid in &uuids {
        println!("{}", uuid);
    }
    
    // Generate with iterator
    let uuid_strings: Vec = (0..5)
        .map(|_| Uuid::new_v4().to_string())
        .collect();
    
    println!("{:?}", uuid_strings);
}

Best Practices

  • Use UUID v4 for general-purpose random identifiers
  • Use UUID v7 for database primary keys (time-sortable)
  • Enable only the features you need in Cargo.toml
  • Use Uuid::parse_str() with proper error handling
  • Enable serde feature for JSON serialization
  • Store UUIDs as native UUID type in PostgreSQL for best performance

Ready to use what you learned?

Try UUID Generator now