How to calculate and validate the Colombian NIT check digit, with code

The modulo-11 algorithm with prime weights used by Colombia's NIT, a worked example and Python and JavaScript functions tested with real cases, plus what the validation cannot tell you.

In this article
In 30 seconds

The NIT check digit is computed by multiplying each digit, right to left, by a series of primes (3, 7, 13…), summing and taking the remainder modulo 11; it catches typing errors, not whether the taxpayer exists.

1. What the check digit is#

A Colombian NIT is written as 890.903.938-8: the last number, after the hyphen, is the check digit (DV, from dígito de verificación). It is computed from the other digits with a modulo-11 method and detects typing errors when the number is captured in a form, an invoice or a database.

Validating the DV is a mathematical check. A NIT with the right DV may belong to no taxpayer, and a nonexistent one can pass the validation. To confirm that a taxpayer exists you have to consult the RUT or the DIAN's services.

Documentation: Siempre al Día: NIT check digit (Spanish) ↗

2. The algorithm step by step#

The sources consulted agree on the steps: take the NIT digits without the DV, from right to left; multiply each by its weight from the prime series 3, 7, 13, 17, 19, 23, 29, 37, 41, 43, 47, 53, 59, 67 and 71; add the products and take the remainder of dividing by 11. If the remainder is 0 or 1, that is the DV; if it is larger, the DV is 11 minus the remainder.

Digit (right to left)WeightProduct
8324
3721
913117
31751
0190
923207
0290
937333
841328
Total—1,081

With NIT 890903938 (whose published DV in the source is 8), the products add up to 1,081. Since 1,081 divided by 11 leaves a remainder of 3, the DV is 11 − 3 = 8.

One of the guides consulted applies the weights left to right; the calculation that reproduces the published example is the right-to-left one, which is the one this guide's code uses.

Documentation: Lookuptax: Colombia NIT guide (Spanish) ↗ · Actualícese: check digit calculator (Spanish) ↗

3. Code in Python and JavaScript#

Both functions accept the NIT with dots or hyphens, ignore any character that is not a digit and reject numbers longer than 15 digits, the length of the weight series. The test cases are example NITs and their DV calculated with the same method.

python
WEIGHTS = (3, 7, 13, 17, 19, 23, 29, 37, 41, 43, 47, 53, 59, 67, 71)

def check_digit(nit: str) -> int:
    """Check digit (modulo 11) of a NIT without its final digit."""
    digits = [c for c in nit if c.isdigit()]
    if not digits or len(digits) > len(WEIGHTS):
        raise ValueError("the NIT must have between 1 and 15 digits")
    total = sum(int(d) * p for d, p in zip(reversed(digits), WEIGHTS))
    remainder = total % 11
    return remainder if remainder < 2 else 11 - remainder

def is_valid(full_nit: str) -> bool:
    """Validates a NIT with its final digit: '890.903.938-8' or '8909039388'."""
    only = [c for c in full_nit if c.isdigit()]
    return len(only) >= 2 and check_digit("".join(only[:-1])) == int(only[-1])

for nit, dv in [("890903938", 8), ("800197268", 4), ("899999068", 1), ("900123456", 8)]:
    print(nit, check_digit(nit), check_digit(nit) == dv)
print(is_valid("890.903.938-8"), is_valid("890.903.938-7"))
Python 3, no dependencies. Prints four checks as True, then True/False for a correctly and a wrongly typed NIT.
javascript
const WEIGHTS = [3, 7, 13, 17, 19, 23, 29, 37, 41, 43, 47, 53, 59, 67, 71];

function checkDigit(nit) {
  const digits = [...String(nit)].filter(c => c >= "0" && c <= "9").reverse();
  if (digits.length === 0 || digits.length > WEIGHTS.length) throw new Error("the NIT must have between 1 and 15 digits");
  const total = digits.reduce((acc, d, i) => acc + Number(d) * WEIGHTS[i], 0);
  const remainder = total % 11;
  return remainder < 2 ? remainder : 11 - remainder;
}

function isValid(nitCompleto) {
  const only = [...String(nitCompleto)].filter(c => c >= "0" && c <= "9");
  return only.length >= 2 && checkDigit(only.slice(0, -1).join("")) === Number(only.at(-1));
}

console.log(checkDigit("890903938"), isValid("890.903.938-8"), isValid("890.903.938-7"));
JavaScript (Node.js). Prints 8 true false.

Documentation: Python: str.isdigit ↗ · MDN: Array.prototype.reduce ↗

4. What the validation does not tell you#

The DV only proves that the digits are consistent with each other. Three things stay out:

  • Existence: a NIT with a correct DV may not be registered in the RUT.
  • Identity: it does not say who owns it or whether it is active.
  • Document type: a natural person's ID number is validated with the same method when used as a NIT, but a number that is not a NIT can match by chance.

Validate the DV in the form to ask the user to fix a typing error, and confirm against the official source when the data has consequences, such as an electronic invoice.

5. Good practices when implementing it#

  • Store the NIT and the DV separately, and compute the DV when displaying to detect corrupted data.
  • Normalize before comparing: remove dots, spaces and hyphens to find duplicates.
  • Write tests with known NITs, including those that give remainder 0 and 1, because that is where implementations with a rule error break.
  • Do not use this validation as a security control or as proof of identity.

Go deeperPostgreSQL: Find the Right Index with EXPLAIN

6. Keep your numbers current#

The weights and the modulo-11 rule are stable, but DIAN regulation on the NIT and the RUT changes. The sources of this guide are accounting and tax guides read on October 18, 2026; confirm with the DIAN before using the validation in regulated processes.

  • Check the official source again when integrating with electronic invoicing.
  • Include tests with remainders 0 and 1 in your suite.
  • If you store tax IDs from other countries, do not apply this rule to them.

Sources and scope

Documentation checked on October 18, 2026. Examples and decision criteria are editorial proposals; adapt them to your application's contract and validate them in an authorized test environment.

Compare these options

Compare databases

Review pricing, limits, conditions and sources for each option.

Open comparison
Advice

Is your case different?

Tell us your context and the options you're weighing. We reply with criteria and sources, and never sign you up for anything.

Request advice