It Started With Someone Else's Terrible Code
There I was, innocently profiling our account management system, trying to figure out why creating a new organization took forever. What I found made me simultaneously frustrated and fascinated.
The code was generating organization slugs. Simple enough, right? Except it was doing something spectacularly inefficient: it would fetch every single organization from the database, count them in memory, and then generate a slug like personal-organization-47
. For the 47th organization. By fetching all 46 previous ones. And filtering by a regex.
Not only was this painfully slow, but it was also racing against itself. Two simultaneous requests? Congratulations, you might get duplicate slugs.
The "Good Enough" Fix
I needed something fast, so I threw together a Python-based dictionary generator. Pick a random adjective, pick a random noun, smash them together with a number. brave-falcon-23
. clever-symphony-891
. Simple, memorable, and most importantly—it didn't fetch the entire database.
For uniqueness, I used the naïve approach: try to insert into the database, regenerate on conflict. With a capacity of roughly 10 million possible combinations and far fewer expected users, the collision probability was acceptably low.
It worked. It was fast enough. I moved on to other things.
Then I Got Curious
A few weeks later, I started thinking: what if I could make this actually good? What if the slug generation could be:
- Deterministic - same seed and sequence always produces the same result
- Unique - guaranteed no collisions within a series
- Fast - because why not?
- Configurable - let users define their own patterns
I wanted a pattern language. Something like {adjective}-{noun}-{number:2x}
that would generate brave-falcon-7a
or clever-symphony-3f
. And I wanted it to be fun.
Let me show you what I mean by fun. Here are some real patterns SlugKit can generate:
(Almost) fake shell commands:
djpeg bathe --neurogenic
sha224sum endeavor --statistical
Royalty titles:
Conjectural Palooka XII the Numskull
Supersonic Maturation CI the Fraud
Case mutations just because I can:
uNFLUctUAtiNg-AbioTRopHy-55
sUBLiMe-ABsolUtioN-00
I won't post here the slugs that are results of +nsfw
tag, but id does swear like a drunk pirate.
This is when SlugKit stopped being a quick fix and became a project.
The Performance Journey: Python → PostgreSQL → C++
Python: The Prototype
My first real experiments were in Python. I built a simple pattern parser, added dictionary filtering, implemented Fisher-Yates shuffling for uniqueness. It worked.
Then I loaded a 40,000-word noun dictionary.
The shuffling became noticeably slow. Not catastrophically slow, but slow enough to bother me. And caching the shuffled results meant storing massive arrays in memory.
PostgreSQL: The "Database Will Save Me" Phase
"Maybe the database can do this faster?" I thought, with the optimism of someone about to learn a lesson.
I moved the permutation logic into PostgreSQL functions. PL/pgSQL handling the pseudo-random generation, indices speeding up lookups.
It was... marginally better? But still not fast. And now I had complicated database functions to maintain.
C++: The "Fine, I'll Do It Properly" Decision
I was frustrated. I wanted performance. And honestly? I missed writing C++.
So I rewrote the entire thing in C++ using the userver framework. No more database functions. No more Python dictionaries. Just pure, compiled, optimized code handling slug generation.
This is when things got interesting.
The Algorithm Evolution
Fisher-Yates: Simple But Slow
The Fisher-Yates shuffle is elegant: shuffle the entire dictionary once, then iterate through it for guaranteed uniqueness. Perfect for small dictionaries.
Terrible for large ones. With a 40K-word dictionary, the initial shuffle was expensive, and caching the results consumed significant memory. I needed something better.
Feistel Networks: Beautiful But Limited
Feistel networks are cryptographically sound permutation algorithms. They work by applying multiple rounds of transformations, producing pseudo-random but deterministic mappings. Perfect for my needs!
Except for one problem: they work beautifully with powers of 2 (256, 1024, 65536), but most dictionaries aren't power-of-2 sized. I had 41,872 nouns. The classic Feistel approach didn't directly apply.
I experimented with cycle walking (keep generating until you hit a valid value), but the variable-time nature bothered me.
Linear Congruential Generators: The Pragmatic Choice
For non-power-of-2 dictionary sizes, I ended up using Linear Congruential Generators (LCGs). They're simple, fast, and produce good-enough permutations for my use case:
output = (multiplier * sequence + increment) % dictionary_size
The key insight: derive the multiplier and increment from the seed using a hash function. Same seed always produces the same sequence. Different seeds produce different sequences. Constant time. Constant space.
For power-of-2 dictionaries, I kept Feistel networks — they're faster and cryptographically stronger.
The Sequential Slug Problem
There was another challenge I hadn't anticipated: capacity calculation and slug quality.
The naïve approach would be to treat each placeholder like a digit in a number system. With pattern {adjective}-{noun}-{number:2x}
, you'd cycle through all adjectives first (keeping noun and number constant), then increment noun, cycle through adjectives again, and so on.
This maximizes capacity (multiply all placeholder sizes together), but it creates a terrible user experience. You'd generate thousands of sequential slugs that differ by only one word:
happy-falcon-7a
sad-falcon-7a
brave-falcon-7a
clever-falcon-7a
...
(17,000 more adjectives later)
happy-penguin-7a
Not fun. Not random-looking. Just boring.
The solution: Advance all placeholders simultaneously. Each new slug changes every component. The sequence feels unpredictable and interesting.
The catch: Capacity drops from multiplication to LCM (Least Common Multiple) of all placeholder capacities. With 17K adjectives, 41K nouns, and 256 hex numbers, you'd lose significant capacity.
The fix: Between pattern parsing and generation, the generator selectively adjusts dictionary sizes to the nearest prime number less than their actual size—but only when this adjustment actually improves the overall LCM. Primes have no common factors, so this optimization recovers much of the lost capacity while keeping the sequence fun and unpredictable.
It's a small optimization that makes a huge difference in the quality of generated slugs. Performance matters, but so does the experience of using them.
The Breakthrough: Caching
The real performance win came from an embarrassingly simple optimization: dictionary caching.
Every time someone requested {adjective:+pos}
or {noun:==5}
(5-letter nouns), I was filtering the dictionary from scratch. Even with optimized indexing, this was expensive.
So I added a cache. Filter once, store the result, reuse it forever.
The results were dramatic:
Dictionary Filtering:
- Before: 200µs average
- After: 68-79ns
- Improvement: 99.96%
Full Slug Generation:
- Simple pattern (
{verb}-{adverb}
): 73µs → 903ns - Complex pattern (9 components): 916µs → 3.9µs
Suddenly, slug generation wasn't just "fast enough." It was fast.
Current Performance
Today, SlugKit generates slugs in 0.5-5µs depending on pattern complexity. That's 200,000+ slugs per second *per core*. With C++ at my disposal, I can scale across all available cores — though currently it's limited to 10% CPU in the development environment, CPU limits don't come cheap (production can burn through all the cycles it needs).
The individual operations are even faster:
- FNV1a hashing: 0.7-11ns depending on string length
- Feistel permutation: 3.5ns (constant time regardless of dictionary size!)
- Dictionary lookup: 191-344ns (barely scales with dictionary size)
- Hex number generation: 22-26ns
For the curious, detailed benchmarks are available here.
The DSL Evolution
While optimizing performance, the pattern language kept growing. What started as {adjective}-{noun}
evolved into:
Number formats:
- Decimal:
{number:8d}
→00042891
- Hex:
{number:4x}
→7a3f
- Roman:
{number:3R}
→XLII
(because why not?)
Case transformations:
- Title:
{Adjective}
→Brave
- Upper:
{NOUN}
→FALCON
- Mixed:
{AdJeCtIvE}
→BrAvE
(using Feistel-based deterministic randomization)
Semantic filtering:
-
{adjective:+pos}
- only positive adjectives -
{noun:==7}
- only 7-letter nouns -
{verb:+emo}
- emotional verbs
(Funny story: Every AI agent that tries SlugKit immediately wants {noun:+tech}
. The tag doesn't exist yet, but given the consistent demand, re-tagging dictionaries with technical terminology just jumped up my priority list.)
Special sequences:
-
{special:4-8}
- random special characters -
{emoji:+face}
- emoji with face-related semantics
The latest addition is emoji support with semantic tagging. You can generate {emoji:+happy}
or {emoji:+animal}
and get contextually appropriate emoji in your slugs.
From Generator to SaaS
At some point, I realized: this is actually useful. Not just for me, but for anyone who's ever stared at a UUID and thought "there has to be a better way."
So SlugKit became a service. Multi-tenant infrastructure, API with streaming support, Python and TypeScript SDKs, comprehensive documentation. The full treatment.
The infrastructure and frontend development is a whole other story (involving 5 C++ microservices, monitoring, and my ongoing battle with making frontend behave). But the core generator—the part I'm genuinely proud of—can pump out hundreds of thousands of unique, memorable, human-readable identifiers per second.
What I Learned
Performance optimization is addictive. It started as "this should be faster" and became "how fast can I actually make this?"
Simple optimizations have massive impact. The dictionary cache was maybe 50 lines of code. It improved performance by 99.96%.
Fun matters. I spent time implementing Roman numerals and emoji support because they made me laugh. Turns out, they can make users happy too.
The right language matters. Python was perfect for prototyping. PostgreSQL seemed clever but wasn't. C++ was the right choice for the performance I wanted — even if it meant more development complexity.
Deterministic chaos is beautiful. There's something elegant about generating seemingly random results that are actually perfectly predictable and reproducible.
Check It Out
SlugKit is live at dev.slugkit.dev. Free beta with generous limits (10,000 operations/day), and the generator engine is open source at github.com/slugkit/slugkit-generator.
Want to try it without signing up? The browser-based playground lets you experiment with pattern syntax and see results instantly. It's the fastest way to understand what SlugKit can do.
Whether you need memorable URLs, user handles, order IDs, or just want to generate ridiculous fantasy names, give it a try. And if you find bugs or have feedback, you might just earn one of the 50 unlimited Friends & Family plans I'm giving to early contributors.
Because ultimately, SlugKit exists because someone wrote personal-organization-N
and made me frustrated enough to fall down a rabbit hole. Sometimes the best projects start with someone else's terrible code.
Top comments (0)