Generate UUID in Rust
The uuid crate on crates.io is the Rust standard — CSPRNG-backed, zero unsafe, no_std compatible, and serde-ready. Uuid::new_v4() in one line.
Quick Reference
| Function | Version | Sortable | Use Case |
|---|---|---|---|
| Uuid::new_v4() | v4 | No | General purpose — session IDs, record IDs, API keys |
| Uuid::now_v7() | v7 | Yes | Database PKs, event logs — time-ordered, B-tree friendly |
| Uuid::new_v5() | v5 | No | Deterministic — same namespace + name always gives same UUID |
| Uuid::parse_str() | any | — | Parse and validate an existing UUID string |
Primary Implementation
use uuid::Uuid;
fn main() {
// UUID v4 — random, CSPRNG-backed via getrandom crate
let id = Uuid::new_v4();
println!("{}", id);
// → f47ac10b-58cc-4372-a567-0e02b2c3d479
// As a hyphenated string
let id_str = id.to_string();
// As a simple (no-hyphen) string
let id_simple = id.simple().to_string();
// → f47ac10b58cc4372a5670e02b2c3d479
// As raw bytes (16 bytes, stack-allocated)
let id_bytes: [u8; 16] = *id.as_bytes();
// Parse and validate an existing UUID string
match Uuid::parse_str("f47ac10b-58cc-4372-a567-0e02b2c3d479") {
Ok(parsed) => println!("Version: {:?}", parsed.get_version()),
Err(e) => eprintln!("Invalid UUID: {}", e),
}
// Generate multiple UUIDs
let ids: Vec = (0..5).map(|_| Uuid::new_v4()).collect();
}
All UUID Versions
UUID v4 — Random (recommended default)
// Cargo.toml: uuid = { version = "1", features = ["v4"] }
use uuid::Uuid;
let id = Uuid::new_v4();
println!("{}", id); // → "550e8400-e29b-41d4-a716-446655440000"
UUID v7 — Time-ordered (database PKs)
// Cargo.toml: uuid = { version = "1", features = ["v7"] }
use uuid::Uuid;
// Millisecond-precision timestamp prefix + random suffix
// IDs generated later always sort after earlier ones
let id = Uuid::now_v7();
println!("{}", id); // → "018e8f6a-1b2c-7d3e-9f4a-5b6c7d8e9f0a"
UUID v5 — Deterministic / Namespace-based
// Cargo.toml: uuid = { version = "1", features = ["v5"] }
use uuid::Uuid;
// SHA-1 hash of namespace + name — same inputs always produce the same UUID
let id = Uuid::new_v5(&Uuid::NAMESPACE_DNS, b"example.com");
println!("{}", id); // → always "cfbff0d1-9375-5685-968c-48ce8b15ae17"
// Custom namespace for your application
let my_ns = Uuid::new_v4(); // generate once, store as a constant
let record_id = Uuid::new_v5(&my_ns, b"user:42");
UUID v3 — MD5 Namespace (legacy)
// Cargo.toml: uuid = { version = "1", features = ["v3"] }
use uuid::Uuid;
// MD5-based — prefer v5 (SHA-1) for new code
let id = Uuid::new_v3(&Uuid::NAMESPACE_DNS, b"example.com");
println!("{}", id);
Real-World Use Cases
1. Axum web handler — request tracing ID
use axum::{middleware::Next, response::Response, http::Request};
use uuid::Uuid;
// Axum middleware that injects a request ID into every response
pub async fn request_id_middleware<B>(
mut req: Request<B>,
next: Next<B>,
) -> Response {
let request_id = Uuid::new_v4().to_string();
req.headers_mut().insert(
"x-request-id",
request_id.parse().unwrap(),
);
let mut response = next.run(req).await;
response.headers_mut().insert(
"x-request-id",
request_id.parse().unwrap(),
);
response
}
2. sqlx — UUID primary key in PostgreSQL
use sqlx::PgPool;
use uuid::Uuid;
use serde::{Deserialize, Serialize};
// Cargo.toml: uuid = { version = "1", features = ["v4", "serde"] }
#[derive(Debug, Serialize, Deserialize)]
struct User {
id: Uuid, // Store as Uuid type, not String
name: String,
}
async fn create_user(pool: &PgPool, name: &str) -> Result<User, sqlx::Error> {
let user = sqlx::query_as!(
User,
"INSERT INTO users (id, name) VALUES ($1, $2) RETURNING id, name",
Uuid::new_v4(),
name
)
.fetch_one(pool)
.await?;
Ok(user)
}
3. Event sourcing — deterministic event IDs
use uuid::Uuid;
const EVENT_NAMESPACE: Uuid = Uuid::from_bytes([
0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1,
0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8,
]);
// Idempotent: same event always gets the same UUID
fn event_id(source: &str, event_type: &str, timestamp: &str) -> Uuid {
let key = format!("{}:{}:{}", source, event_type, timestamp);
Uuid::new_v5(&EVENT_NAMESPACE, key.as_bytes())
}
fn main() {
let id1 = event_id("payments", "charge.created", "2026-05-01T12:00:00Z");
let id2 = event_id("payments", "charge.created", "2026-05-01T12:00:00Z");
assert_eq!(id1, id2); // always true — safe to retry
}
Common Mistakes
Forgetting to enable the right Cargo features
The uuid crate ships with no features enabled by default. Calling Uuid::new_v4() without features = ["v4"] in Cargo.toml is a compile error. Enable exactly what you need: ["v4", "v7", "serde"].
Storing UUIDs as String instead of Uuid
The Uuid type is a 16-byte stack-allocated value. Storing it as a String (36 bytes + heap allocation) wastes memory and loses type safety. Pass Uuid around and only call .to_string() at the boundary.
Using UUID v1 in web services
UUID v1 embeds the server's MAC address and a timestamp, leaking network topology and making IDs predictable. Use v4 for random IDs or v7 for time-ordered IDs in web services.
How It Works
The uuid crate delegates entropy to the getrandom crate, which calls the OS CSPRNG directly — /dev/urandom on Linux/macOS and BCryptGenRandom on Windows. No userspace RNG state is maintained.
The Uuid type is a newtype wrapper around [u8; 16] — a 16-byte value type stored entirely on the stack. Zero heap allocation, zero unsafe code in the public API.
With the serde feature, Uuid automatically serializes to a hyphenated string in JSON and deserializes back, with validation included.
Output Formats
id.to_string() / format!("{}", id)
f47ac10b-58cc-4372-a567-0e02b2c3d479
id.simple().to_string()
f47ac10b58cc4372a5670e02b2c3d479
id.as_bytes() — [u8; 16]
[0xf4, 0x7a, 0xc1, 0x0b, ...]
id.as_u128()
324716517733474852975027497220825710713
Best Practices
Store and pass Uuid values — only convert to string at API/DB boundaries.
Enable the serde feature for automatic JSON serialization with validation.
Use Uuid::now_v7() for database primary keys — sequential inserts avoid B-tree fragmentation.
Performance
Rust generates roughly 10–50 million UUIDs/second on modern hardware. The Uuid type is stack-allocated (16 bytes), so there is zero heap allocation per UUID.
The crate is no_std compatible with the getrandom feature, making it suitable for embedded targets.
Installation
# Cargo.toml
[dependencies]
uuid = { version = "1", features = ["v4", "v7", "serde"] }
The uuid crate is on crates.io. Enable only the features you need to keep compile times minimal.
Security
Entropy source: getrandom crate → OS CSPRNG (/dev/urandom on Linux/macOS, BCryptGenRandom on Windows). Cryptographically secure.
The uuid crate contains zero unsafe code in its public API. Suitable for session tokens, CSRF tokens, and security-sensitive IDs.