Skip to content

Comparison with other libraries

Several libraries on npm validate Spanish IDs. They differ in which documents they cover, how they treat what users type, and what they tell you when a number is wrong. This page compares their features; the benchmarks compare their speed, size and agreement with SPEC.md.

Checked on 1 October 2026 against each library's README, package.json and npm page. Versions and sizes come from the benchmark results.

Features of the Spanish ID libraries on npm, with the sources each row was checked against
LibraryTypesK/L/MNormalizes inputResult objectLocalized messagesTest-data generatorsSchemasModulesSize, any type (min+gzip)Last releaseSources
nif-dni-nie-cif-validation this buildDNI, NIE, CIF, K/L/Myesyesyes: code, SPEC rule, messageEN, ES, CA, EU, GLyesZod, Valibot, YupESM + CJS929 Bthis releaseREADME npm
spain-id 1.1.14DNI, NIE, CIFnopartialno (type only)nononoESM + CJS583 B2026-06-12README npm
better-dni 4.4.2DNI, NIEnoseparate normalize()nonoyesnoCJS / UMD only1,134 B2021-05-30README npm
dni-js 1.0.0DNI, NIEnopartialnonononoCJS only882 B2026-08-08README npm
stdnum 1.12.6DNI, NIE, CIF, K/L/M, and about 90 countriesyesyesyes: error classEnglish onlynonoESM + CJS51,063 B2026-08-01README npm
validator.js isIdentityCard(x, "ES") 13.15.35DNI, NIEnonononononoESM (deep imports) + CJS2,539 B2026-04-02README npm
validator.js isTaxID(x, "es-ES") 13.15.35DNI, NIE, K/L/MyesnononononoESM (deep imports) + CJS6,537 B2026-04-02README npm
@maistik/validate-nif 2.0.1DNI, NIE, CIFnopartialpartial: parse(), without the reasonnononoESM + CJS456 B2026-06-14README npm
@kreyo/nif-validator 0.1.0DNI, NIE, CIFopt-inpartialnonononoESM + CJS533 B2026-04-29README npm
jsvat 2.5.4EU VAT numbers (ES + NIF)yesyesyes: validity and countrynononoESM + CJS1,186 B2024-12-12, deprecatedREADME npm

What the columns mean:

  • Types: the documents the library validates. K/L/M NIFs belong to people without a DNI or an NIE (KLM-1).
  • Normalizes input: whether it accepts what users type (lower case, spaces, dots, hyphens) without a separate step. “Partial” means some of these.
  • Result object: whether it can tell you more than yes or no, such as the type or the reason.
  • Size: one validator of any type, minified and gzipped, as measured by the benchmark.
  • Sources: each library’s README and npm page, which every row was checked against on the date above.

Where another library is the better choice

Section titled “Where another library is the better choice”
  • Many countries: stdnum. stdnum, the JavaScript port of python-stdnum, validates the identifiers of about 90 countries with one API, every Spanish type included. If you need several countries, it is a good choice. This library does only Spain, and goes deeper there.
  • The smallest bundle: spain-id or @maistik/validate-nif. For one validator, spain-id and @maistik/validate-nif are smaller than this library: see the bundle sizes. They don’t accept K/L/M NIFs or the old NIE form, and they don’t say why a number is invalid, so they spend fewer bytes. If every byte counts and you don’t need those, they are fine choices.
  • Many kinds of string: validator.js. If you already use validator.js for emails and URLs, its two Spanish functions may be enough for DNIs and NIEs. It has no CIF check.
  • Every type, K/L/M NIFs and the old 10-character NIE included, and the official control rules for CIFs (CIF-3).
  • Sources for every rule: each one has an ID and a citation in SPEC.md, and every error names the rule that failed.
  • The reason, as an error code, a SPEC rule and a message in English, Spanish, Catalan, Basque or Galician.
  • Normalization and the canonical form to store, test-data generators, and Zod, Valibot and Yup schemas.

Where libraries disagree with SPEC.md, the benchmarks count the disagreements of each one, and say which follow from a decision that SPEC.md documents.