Exid - Elixir Xid

An Elixir implementation of the globally unique ID generator xid, suited for web scale, ported from the Go xid package.

Overview

Exid generates 12-byte globally unique IDs using the MongoDB Object ID algorithm:

Why Xid?

String Format

IDs are encoded as 20-character strings using base32 hex alphabet (0-9, a-v):

iex> id = Exid.new()
iex> Exid.to_string(id)
"c0nsb7f1en2k9b5ls9bg"

Installation

Add exid to your list of dependencies in mix.exs:

def deps do
  [
    {:exid, "~> 0.1.0"}
  ]
end

Quick Start

# Initialize (must be called once at application startup)
Exid.init()

# Generate a new ID
id = Exid.new()

# Convert to string
id_string = Exid.to_string(id)

# Parse from string
{:ok, id} = Exid.from_string(id_string)

# Extract components
timestamp = Exid.time(id)
machine_id = Exid.machine(id)
process_id = Exid.pid(id)
counter = Exid.counter(id)

# Sort IDs (they're sortable!)
ids = [Exid.new(), Exid.new(), Exid.new()]
sorted = Exid.sort(ids)

API Reference

Generation

Conversion

Inspection

Comparison & Sorting

Utilities

Machine ID Detection

Xid automatically detects the machine ID using the following priority order:

  1. Environment Variable: XID_MACHINE_ID (must be a number 0-16777215)
  2. Platform-Specific ID:
    • Darwin (macOS): ioreg -rd1 -c IOPlatformExpertDevice → IOPlatformUUID
    • FreeBSD: sysctl kern.hostuuid
    • OpenBSD: sysctl hw.uuid
    • Linux: /etc/machine-id or /sys/class/dmi/id/product_uuid
    • Windows: Registry HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography → MachineGuid
  3. Hostname Hash: SHA256 hash of system hostname
  4. Random: Cryptographically random bytes (fallback)

Setting Machine ID

# Override with environment variable
export XID_MACHINE_ID=12345

# Must be a valid 24-bit number (0-16777215)
export XID_MACHINE_ID=16777214  # OK
export XID_MACHINE_ID=16777216  # Error: out of range

Cross-Compatibility with Go xid

This implementation is compatible with the Go xid package. IDs generated in Go can be decoded in Elixir and vice versa:

# Decode Go-generated ID
{:ok, id} = Exid.from_string("9m4e2mr0ui3e8a215n4g")

# Verify components match Go implementation
Exid.time(id)     # => 1300816219
Exid.machine(id)  # => <<0x60, 0xf4, 0x86>>
Exid.pid(id)      # => 58408 (0xe428)
Exid.counter(id)  # => 4271561

ETS Table

Xid uses an ETS table named :xid_counter to maintain the atomic counter for generating unique IDs. The table is created automatically on application startup.

Testing

Run the test suite:

mix test

Tests include:

They are mostly ported from the Go xid package, with some additional tests and benchmarks.

Running Benchmarks

mix run benchmark/benchmark.exs

References

License

The Elixir port maintains compatibility with the original Go implementation by Olivier Poitrey, licensed under the MIT License.