Reach for a faker library and you get a string that looks plausible and stops there. Eleven digits that resemble a PESEL. An email with an @ in the middle. An IBAN with the right number of characters. It looks like data, so it goes into your fixtures, your tests go green, and everyone moves on. The trouble starts the day a real record — or a real user — shows up and the assumptions baked into that fake data turn out to be wrong.
The gap is subtle because fake data fails in the most reassuring way possible: it passes. A test seeded with a structurally-broken PESEL will happily exercise your create-user flow, your database insert, and your confirmation email, and report success for all three — because none of those steps ever validated the number. The one code path that would have caught the problem is the one your fake data was too shallow to reach.
Checksums are the part fakers skip
A PESEL is not eleven random digits. The eleventh is a checksum computed over the first ten with a fixed weight vector — get any digit wrong and the whole number is invalid. The same is true of a NIP, a REGON, an IBAN, and the national identifiers of every EU country: Denmark’s CPR, Italy’s codice fiscale, the Netherlands’ BSN, France’s NIR, Sweden’s personnummer. Each carries its own checksum scheme — Luhn, mod-11, mod-97, Verhoeff, ISO 7064 — and each rejects a number that does not satisfy it.
If your test data ignores the checksum, your validation layer is never exercised. You ship a `isValidPesel()` function that has only ever been called with input it was always going to accept, and it holds up right until someone pastes a transposed digit. Compare a hand-rolled fake against the real thing:
// Typical faker output — 11 random digits, checksum ignored
"44051401458" // isValidPesel() → false (but nothing ever checks)
// Real Fake Data — checksum digit is correct by construction
GET /v1/pl/person?seed=7421
{
"data": {
"name": "Magdalena",
"surname": "Wróbel",
"birthDate": "1995-09-02",
"pesel": "95090265040" // isValidPesel() → true
}
} Real Fake Data generates every identifier with a correct, country-specific checksum, so it passes the exact validators your production code runs — including the encoded facts, like the birth date and sex a PESEL or CPR carries in its own digits. The data is synthetic and tied to no real person, but structurally it is indistinguishable from a genuine record.
Realism goes beyond the checksum
Validity is not only about numbers. An address built from a random street name and a random postal code will pass a naive form but fall apart the moment anything downstream expects the two to agree. Our Polish address generator draws from the PRG dataset — 8.57 million real address points — so the street, the city, and the postal-code prefix are mutually consistent, the way they are on an actual envelope:
{
"data": {
"streetFullName": "ul. Długa",
"buildingNumber": "153",
"postalCode": "00-632",
"cityName": "Warszawa",
"voivodeshipName": "mazowieckie"
}
} That coherence matters as soon as you screenshot a demo, geocode an address, or validate a postal code against a city. Data that is internally inconsistent is just a slower way of finding out your fixtures were never realistic.
What you actually get from it
- Your validators run in tests instead of only in production — the rejection paths get exercised, not just the happy path.
- Seeded staging behaves like the real thing: parsers parse, constraints hold, foreign keys line up.
- When something breaks, it breaks for a real reason — not because the fixture was garbage to begin with.
- You can hand the same data to a checksum library, a geocoder, or a downstream partner API and it survives the round-trip.
The goal is not realism for its own sake. It is confidence: fewer false failures in CI, and real bugs caught before your users find them.
Fake data that only looks right is a liability disguised as a convenience. Fake data that is valid by format — checksummed, internally consistent, drawn from real geography — is the thing that lets a staging environment stand in for production. That distinction is the whole reason this product exists.