Generating UUIDs in Swift
On this page
Apple platforms ship with a native UUID type in Foundation. It covers v4 (random) out of the box. For v7, you need a small dependency.
Quick start
import Foundation
let id = UUID()
print(id.uuidString) // "0E6F1B8C-2C33-4F1F-9C0B-2A3D4E5F6A7B" (uppercase)
UUID is a struct — value semantics, Hashable, Codable, Sendable. Comparison via == works as expected.
Note: uuidString returns uppercase, unlike most other languages. If you need lowercase for cross-platform consistency:
let id = UUID().uuidString.lowercased()
Parsing
let s = "0e6f1b8c-2c33-4f1f-9c0b-2a3d4e5f6a7b"
if let id = UUID(uuidString: s) {
// valid
}
UUID(uuidString:) is a failable initializer that accepts the canonical form (case-insensitive). It does not accept braced or no-hyphens forms.
Codable / JSON
import Foundation
struct User: Codable {
let id: UUID
let email: String
}
let user = User(id: UUID(), email: "alice@example.com")
let data = try JSONEncoder().encode(user)
// {"id":"0E6F1B8C-2C33-4F1F-9C0B-2A3D4E5F6A7B","email":"alice@example.com"}
JSONEncoder serializes UUIDs as their uuidString — uppercase by default. To match the lowercase convention used by Postgres / most JS / most APIs, use a custom encoder:
let encoder = JSONEncoder()
encoder.dataEncodingStrategy = .base64
// no built-in UUID strategy, but you can encode manually:
extension UUID {
var lowercaseString: String { uuidString.lowercased() }
}
struct User: Codable {
let id: UUID
let email: String
enum CodingKeys: CodingKey { case id, email }
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id.lowercaseString, forKey: .id)
try container.encode(email, forKey: .email)
}
}
For most projects, normalize at the API boundary (server-side) rather than fighting the platform default.
v7 with swift-uuidv7
// Package.swift
.package(url: "https://github.com/wabiverse/swift-uuid-v7", from: "0.1.0")
import UUIDv7
let id = UUIDv7.generate()
Or use a tiny inline implementation if you’d rather avoid the dependency:
import Foundation
extension UUID {
static func v7() -> UUID {
let now = UInt64(Date().timeIntervalSince1970 * 1000)
var bytes = [UInt8](repeating: 0, count: 16)
// 48-bit timestamp
for i in 0..<6 {
bytes[i] = UInt8((now >> (40 - 8 * i)) & 0xff)
}
// 74 random bits
var rand = [UInt8](repeating: 0, count: 10)
_ = SecRandomCopyBytes(kSecRandomDefault, 10, &rand)
bytes[6] = (rand[0] & 0x0f) | 0x70 // version 7
bytes[7] = rand[1]
bytes[8] = (rand[2] & 0x3f) | 0x80 // variant RFC 4122
for i in 9..<16 {
bytes[i] = rand[i - 6]
}
return UUID(uuid: (bytes[0], bytes[1], bytes[2], bytes[3],
bytes[4], bytes[5], bytes[6], bytes[7],
bytes[8], bytes[9], bytes[10], bytes[11],
bytes[12], bytes[13], bytes[14], bytes[15]))
}
}
let id = UUID.v7()
Production code should prefer a maintained library. The above is fine for understanding the structure.
SwiftData
import SwiftData
@Model
final class User {
@Attribute(.unique) var id: UUID
var email: String
init(email: String) {
self.id = UUID()
self.email = email
}
}
SwiftData uses UUID as a primary-key-compatible type natively. For v7, replace UUID() with your v7 generator.
Core Data
For Core Data entities, mark the attribute as a UUID type in the data model. Use a default value or generate in awakeFromInsert():
import CoreData
class User: NSManagedObject {
@NSManaged var id: UUID
@NSManaged var email: String
override func awakeFromInsert() {
super.awakeFromInsert()
id = UUID()
}
}
CloudKit
CloudKit auto-generates record IDs as UUIDs. If you need to control the ID:
let recordID = CKRecord.ID(recordName: UUID().uuidString)
let record = CKRecord(recordType: "User", recordID: recordID)
Bytes
let id = UUID()
withUnsafeBytes(of: id.uuid) { bytes in
let data = Data(bytes: bytes.baseAddress!, count: 16)
// RFC 4122 byte order
}
UUID’s uuid property is a 16-tuple in RFC byte order — matches every non-Microsoft platform. SQL Server uniqueidentifier raw bytes need byte-swapping; see UUID vs GUID.
Comparing
let a = UUID()
let b = a
a == b // true
a.hashValue // works in Sets and Dictionary keys
UUIDs are Comparable since Swift 5.5 — you can sort an array of UUIDs:
let sorted = uuids.sorted()
For v7 UUIDs this gives chronological order. For v4 it’s a stable but meaningless order.
Common pitfalls
uuidStringis uppercase. Lowercase via.lowercased()for cross-platform consistency.UUID(uuidString:)is strict. Doesn’t accept no-hyphens, braced, or URN forms. Strip those manually before parsing.UUID()collisions in single-threaded loops are theoretically possible but practically impossible — see collision probability.- Don’t use UUID v4 for sortable data. If you need creation-time ordering, use v7 or store a separate
Datefield.
Cheat sheet
| Goal | Code |
|---|---|
| Random UUID | UUID() |
| Time-ordered (v7) | UUID.v7() (custom or library) |
| Parse | UUID(uuidString: s) |
| Lowercase string | id.uuidString.lowercased() |
| Bytes | withUnsafeBytes(of: id.uuid) { ... } |
Try the tools
- UUID generator — instant in browser
- UUID v7 generator — for SwiftData / Core Data primary keys
- UUID validator — paste, decode, verify