Skip to content
100% in your browser. Nothing you paste is uploaded — all processing runs locally. Read more →

Generating UUIDs in Rust

On this page
  1. Setup
  2. Quick start
  3. Parsing
  4. Serde / JSON
  5. sqlx integration
  6. Diesel integration
  7. Bytes and byte order
  8. Const UUIDs (compile-time)
  9. WASM / browsers
  10. no_std
  11. Performance
  12. Common pitfalls
  13. Cheat sheet
  14. Try the tools

The uuid crate is the universal Rust UUID library — well-maintained, no-std friendly, with features gated behind flags so you only pay for what you use.

Setup

cargo add uuid --features v4,v7,serde

Each feature flag enables a specific version or capability:

FeatureEnables
v1Time-based (timestamp + node)
v3Name-based (MD5)
v4Random — most common
v5Name-based (SHA-1)
v6v1 with sortable timestamp
v7Unix-ms timestamp + random
v8Custom
serdeserde Serialize/Deserialize
fast-rngUse a faster (non-cryptographic) RNG
jsWASM/JS environments

Quick start

use uuid::Uuid;

fn main() {
    let v4 = Uuid::new_v4();
    let v7 = Uuid::now_v7();
    let v5 = Uuid::new_v5(&Uuid::NAMESPACE_URL, b"https://example.com");

    println!("{}", v4);              // canonical form
    println!("{}", v4.simple());     // no hyphens
    println!("{}", v4.braced());     // {with-braces}
    println!("{}", v4.urn());        // urn:uuid:...
}

Uuid is Copy — a 16-byte value you pass around freely without borrowing. The various format methods return temporary structs that implement Display, so they’re zero-allocation when used with format! / write!.

Parsing

let s = "0e6f1b8c-2c33-4f1f-9c0b-2a3d4e5f6a7b";
let id: Uuid = s.parse()?;          // canonical
let id = Uuid::parse_str(s)?;       // explicit

parse_str accepts canonical, no-hyphens, braced, and URN forms. Invalid input returns uuid::Error.

Serde / JSON

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

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

let u = User { id: Uuid::now_v7(), email: "alice@example.com".into() };
let json = serde_json::to_string(&u)?;
// {"id":"01928a47-3b30-7c5e-9d1a-f0b8c4a7e923","email":"alice@example.com"}

UUIDs serialize to their canonical string by default.

sqlx integration

[dependencies]
sqlx = { version = "0.8", features = ["runtime-tokio", "postgres", "uuid"] }
uuid = { version = "1", features = ["v7", "serde"] }
use sqlx::{PgPool, Row};
use uuid::Uuid;

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

let user: User = sqlx::query_as(
    "SELECT id, email FROM users WHERE id = $1"
)
.bind(id)
.fetch_one(&pool)
.await?;

let id = Uuid::now_v7();
sqlx::query("INSERT INTO users (id, email) VALUES ($1, $2)")
    .bind(id)
    .bind(&email)
    .execute(&pool)
    .await?;

sqlx’s uuid feature enables transparent conversion between PostgreSQL uuid and Rust Uuid.

Diesel integration

[dependencies]
diesel = { version = "2.2", features = ["postgres", "uuid"] }
uuid = { version = "1", features = ["v7"] }
use diesel::prelude::*;
use uuid::Uuid;

#[derive(Insertable, Queryable, Selectable)]
#[diesel(table_name = users)]
struct User {
    id: Uuid,
    email: String,
}

Bytes and byte order

let id = Uuid::new_v4();
let bytes: &[u8; 16] = id.as_bytes();   // borrowed, RFC 4122 order
let owned: [u8; 16] = id.into_bytes();  // owned

let from_bytes = Uuid::from_bytes(owned);

This is RFC 4122 / network byte order. For Microsoft’s GUID byte order (when reading SQL Server uniqueidentifier raw bytes), see UUID vs GUID.

Const UUIDs (compile-time)

use uuid::uuid;

const ORDERS_NS: Uuid = uuid!("8a4c2d6e-1f3b-4a5c-9d8e-7f6a5b4c3d2e");

The uuid! macro parses at compile time, so an invalid literal becomes a compile error rather than a runtime panic.

WASM / browsers

uuid = { version = "1", features = ["v4", "v7", "js"] }

The js feature pulls in getrandom configured to use the browser’s crypto.getRandomValues(). Without it, you’ll get a runtime error in WASM.

no_std

uuid = { version = "1", default-features = false, features = ["v4"] }

Disable default features and pick what you need. The crate works on no_std for embedded use cases.

Performance

ApproachThroughput (single-threaded)
Uuid::new_v4() (default rng)~3M/sec
Uuid::new_v4() with fast-rng~12M/sec
Uuid::now_v7()~5M/sec

Default uses getrandom (cryptographically secure). fast-rng uses rand with a faster (non-secure) PRNG. Don’t use fast-rng for security tokens.

Common pitfalls

Cheat sheet

GoalCode
Random UUIDUuid::new_v4()
Time-ordered (v7)Uuid::now_v7()
Deterministic (v5)Uuid::new_v5(&ns, b"name")
Parses.parse::<Uuid>()
Const UUIDuuid!("0e6f1b8c-...")
Bytes (RFC order)id.as_bytes()
Empty / nilUuid::nil()

Try the tools