Developer Lab · Rust
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, Performance, and Security
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.
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.
Installation
UUID v4 (uuid crate)
# 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.
Frequently Asked Questions
How do I generate a UUID in Rust?
The uuid crate on crates.io is the standard choice. Add uuid = { version = '1', features = ['v4', 'v7'] } to Cargo.toml, then call Uuid::new_v4() for a random UUID or Uuid::now_v7() for a time-ordered one. Enable the serde feature for serialization support.
Is Uuid::new_v4() cryptographically secure?
Yes. Uuid::new_v4() 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 Rust?
UUID v4 (Uuid::new_v4() 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 Rust?
A package or library install may be required. See the Installation section for the recommended approach in Rust.
How do I validate a UUID string in Rust?
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 Rust 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 Rust 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 Rust?
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 Rust 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_v4() 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.