names-db began as a flat union of names gathered from sports data and several one-off imports. Building a generator exposed a semantic problem: a name’s presence in a national register shows usage in that country. It does not prove the language or naming tradition that produced it.
The data problem
Building a reliable name generator sounds deceptively simple: grab a list of names, pick one at random, and you're done. When I started building names-db, my approach was straightforward: aggregate a massive list of names from various sports datasets and one-off CSV imports.
My unique name files were built by stacking various data sources (football rosters, a Japanese name dataset, French prenoms, and even a mix of Nordic and fantasy names). At first, they were just flat arrays of strings without any geographic context or frequency weighting.
This became an issue when I wanted the generator to be region-specific. If I drew a name from the Irish register, I might get "Nusaybah" or "Hadassah." While perfectly valid as names registered in Ireland, they aren't what someone expects when asking for a Gaelic name. The data represented usage, but I needed etymology.
Refining the approach: registers and pools
To solve this, I rebuilt the data model. Instead of just a flat list of strings, each name record became an object containing regional tags and occurrence counts based on official data (like Scotland's NRS babies or Sweden's SCB).
{"name": "Aoife", "regions": ["germany", "ireland", "scotland"], "counts": {"germany": 2, "ireland": 22063, "scotland": 699}}However, just filtering by a region tag wasn't enough. I introduced the concept of "pools" to control how strictly a name is selected via the CLI:
register: The default mode, returning any name officially recorded in that region.exclusive: A stricter heuristic that ensures the name doesn't belong to heavily conflicting regions, increasing the chance of it being culturally specific.morph: An algorithmic approach that breaks down names into common European stems and suffixes, then recombines them to invent entirely new, phonetically plausible names.
The limits of labels
Even with these filters, the line between usage and origin remains blurry. Japan's "exclusive" draws sometimes include romanizations like "Kanehito" (valid string representations, but not native kanji). Meanwhile, the morph pool successfully generates names with a European phonetic shape but makes no guarantees about establishing a true Gaelic or Nordic origin.
Seventeen unit tests cover the software's parsing, region filtering, and CLI logic. But testing software behavior is easy; proving that invented names are linguistically and culturally correct is an entirely different challenge.
What's next: Markov chains
Currently, generating names involves either sampling from existing pools or using the algorithmic morph strategy. But the next step is moving towards statistical modeling.
The plan is to implement a letter-based Markov strategy (order 2 or 3) trained on the exclusive or morph pools, using the frequency counts as weights. Rather than memorizing a dirty global pool, the model will learn the specific orthography of a selected region. Evaluating this won't be about passing unit tests—it will require holding out real names, measuring if the invented strings stay true to the region's phonology, and manually inspecting the failures.
Building names-db started as a data aggregation task, but it quickly turned into an exercise in computational linguistics.
