idmix: A Better Alternative to Sqids for Structured Access Keys
If you've ever needed to generate short, URL-safe identifiers from integers, you've probably encountered Sqids (formerly Hashids). While Sqids is popular and works well for basic use cases, it has significant limitations when building structured access keys or API tokens.
Today I want to introduce idmix - a short ID encoding library that addresses these limitations while adding powerful new features.
The Problem with Current Solutions
Let's say you're building an API key system. You want to encode:
- User ID (uint64)
- Expiration timestamp (uint32)
- Permission flags (uint16)
With Sqids, you'd do something like:
import { encode } from 'sqids';
const key = encode([userId, expiry, perms]);
But there are problems:
- No negative numbers - Sqids only supports non-negative integers
-
No type information - When decoding, you get
[12345, 1690000000, 7]but don't know which is which - Deterministic output - Same input always produces the same string, making keys vulnerable to scanning
- Language inconsistencies - Different language implementations may behave slightly differently
Enter idmix
idmix solves all these problems:
import idmix "github.com/Vanni-Fan/idmix/golang"
m, _ := idmix.New()
// Encode with types preserved
key, _ := m.Encode(uint64(userId), uint32(expiry), uint16(perms))
// → "9XqK2mPpL"
// Decode - types automatically restored
values, _ := m.Decode(key)
uid := values[0].(uint64) // 12345
exp := values[1].(uint32) // 1690000000
perms := values[2].(uint16) // 7
Key Features
1. Type-Aware Encoding
Every value carries its original type information. No external schema needed:
from idmix import IdMix, u16, i64, u32
m = IdMix.new()
key = m.encode(u16(5), i64(-1), u32(40))
values = m.decode(key)
# values[0] is uint16: 5
# values[1] is int64: -1
# values[2] is uint32: 40
2. Nine-Language Interoperability
idmix provides consistent implementations across:
- Go (reference implementation)
- Rust
- Python
- JavaScript/TypeScript
- Java
- C#
- PHP
- C++
- C
Encode in your Go backend, decode in your Python data pipeline or JavaScript frontend - guaranteed compatibility.
3. 32-State Polymorphic Encoding
This is my favorite feature. Same data, different outputs:
m, _ := idmix.New()
key1, _ := m.Encode(uint64(12345)) // "a3K9mP"
key2, _ := m.Encode(uint64(12345)) // "x7Q2nR"
key3, _ := m.Encode(uint64(12345)) // "b5M8vW"
// All decode to the same value
This provides natural obfuscation against brute-force scanning attacks. An attacker can't predict what your keys look like, even if they know the underlying data.
4. Lightweight Self-Validation
Built-in 2-bit XOR checksum catches approximately 75% of random tampering attempts without any additional storage.
5. Performance
idmix is fast. Really fast:
| Operation | vs Sqids (Go) | vs Sqids (Rust) |
|---|---|---|
| Encode [1,2,3] | 47× faster | 12× faster |
| Encode AccessKey | 21× faster | 16× faster |
| Decode AccessKey | 2.4× faster | 4.2× faster |
Comparison Table
| Feature | Sqids | idmix |
|---|---|---|
| Input types | Non-negative integers only | Any integer + short strings |
| Negative numbers | ❌ | ✅ |
| Type self-description | ❌ | ✅ |
| Polymorphic encoding | ❌ | ✅ (32 variants) |
| Self-validation | ❌ | ✅ |
| Multi-language consistency | Partial | Full |
| Blocklist filtering | ✅ | Not needed* |
*idmix's polymorphic encoding makes blocklists unnecessary - just re-encode if you get an undesirable string.
Installation
Go:
go get github.com/Vanni-Fan/idmix/golang
Python:
pip install vanni-idmix
Rust:
cargo add idmix
JavaScript:
npm install @vanni.fan/idmix
Java:
<dependency>
<groupId>io.github.vanni-fan</groupId>
<artifactId>idmix</artifactId>
<version>0.4.0</version>
</dependency>
C#:
dotnet add package Vanni.Idmix
PHP:
composer require vanni/idmix
Use Cases
- API Access Keys - Structured keys with embedded metadata
- Short URLs - More compact than base64-encoded data
- Invite Codes - Embed channel, validity period, etc.
- Device Identification - Cross-platform unique identifiers
- Order/Transaction IDs - Human-readable but information-dense
Conclusion
If you're building anything that needs short, type-safe, cross-language identifiers, give idmix a try. It's particularly well-suited for access key scenarios where you need to embed multiple typed fields.
The library is open source under Apache-2.0 license. I'd love your feedback and contributions!
GitHub: https://github.com/Vanni-Fan/idmix
Have you used Sqids or Hashids before? What limitations have you run into? Let me know in the comments!
Top comments (0)