DEV Community

IBAN validation guide for developers

Length and country format

Every IBAN starts with a 2-letter ISO country code and 2 check digits, followed by a country-specific BBAN whose length is fixed per country - Germany is always 22 characters, the Netherlands 18, Malta 31. A string can be the right shape (letters-then-digits) and still be the wrong length for the country it claims to be from.

The mod-97 checksum (ISO 7064)

This is the part people get wrong or skip:

function isValidIBAN(iban) {
  const clean = iban.replace(/\s+/g, "").toUpperCase();
  if (!/^[A-Z]{2}\d{2}[A-Z0-9]+$/.test(clean)) return false;
  const rearranged = clean.slice(4) + clean.slice(0, 4);
  const numeric = rearranged.replace(/[A-Z]/g, c => (c.charCodeAt(0) - 55).toString());
  // IBANs convert to numbers far too large for JS's Number type (30+ digits),
  // so mod 97 has to be computed in chunks rather than in one BigInt/Number op.
  let remainder = numeric;
  while (remainder.length > 2) {
    const chunk = remainder.slice(0, 9);
    remainder = (parseInt(chunk, 10) % 97) + remainder.slice(chunk.length);
  }
  return parseInt(remainder, 10) % 97 === 1;
}

Move the first 4 characters to the end, convert every letter to its numeric value (A=10 ... Z=35), and the resulting number mod 97 must equal 1. The chunked-modulo loop is the detail that trips up most from-scratch implementations - you can't just do BigInt(numeric) % 97n in older runtimes without a BigInt polyfill, and plain Number silently loses precision past 2^53.

What this does not tell you

A passing checksum means the IBAN is well-formed - not that the account exists, is open, or belongs to who the payer thinks it does. Confirming that needs a live lookup against the bank (or a service like the account-name-matching checks banks now run for fraud prevention), which is a separate, heavier operation than format validation.

For most apps - checkout forms, payout setup, onboarding - steps 1 and 2 are exactly the right amount of validation: fast, no external calls, no third-party uptime dependency. I wrapped both (plus the per-country BBAN structure check) into an endpoint on Validate if you'd rather not own the mod-97 edge cases yourself.

Comments

No comments yet. Start the discussion.