If you've ever built a form in Spain, you know the pain: validating a DNI is straightforward, but then someone enters a NIE, or a company CIF, and suddenly you're copy-pasting regex from a 2009 Stack Overflow answer.
I got tired of that. So I built @polgubau/validar-dni — a tiny, typed, zero-dependency library that handles all three.
What it does
import { validDniCifNie, parseDni } from "@polgubau/validar-dni";
// Simple boolean check
validDniCifNie("12345678Z"); // true
validDniCifNie("12345678A"); // false
// Rich result — tells you what's wrong
parseDni("12345678A");
// {
// isValid: false,
// type: "NIF",
// normalized: "12345678A",
// expectedControl: "Z" ← the correct letter
// }
It covers:
| Type | Format | Example |
|---|---|---|
| NIF (DNI) | 8 digits + letter | 12345678Z |
| NIE | X/Y/Z + 7 digits + letter | X1234567L |
| CIF | Org letter + 7 digits + letter/digit | A58818501 |
| NIE especial | T + 8 digits | T12345678 |
Why not just use a regex?
A regex can check the format. But Spanish identifiers have a control character — a letter or digit derived from the rest of the number using a specific algorithm. A regex can't validate that.
parseDni always returns the expectedControl, even when the input is invalid. So instead of just saying "wrong", you can tell the user "the correct letter is Z".
Architecture
The library uses a Strategy pattern — each document type is an isolated validator implementing a Validator interface:
interface Validator {
matches(normalized: string): boolean;
validate(normalized: string): DniResult;
}
Adding a new document type means creating one file and adding it to the array. Zero changes to existing code.
Tree-shaking
If you only need NIF validation, import just that:
import { nifValidator } from "@polgubau/validar-dni/nif"; // ~115 bytes
vs the full bundle at ~1 KB.
Stats
- Zero runtime dependencies
- 100% branch coverage
- ~1 KB full bundle, ~115 bytes per subpath
- ESM + CJS, full
.d.tstypes - Works in Node, browsers, React, Next.js, Deno
Install
npm install @polgubau/validar-dni
GitHub: github.com/PolGubau/validar-dni
Built with TypeScript, bundled with tsup, linted with Biome. MIT licensed.
Would love feedback, especially if there are edge cases I'm missing.
To know more details check https://www.polgubau.com/
Top comments (0)