Driver's license (CNH)

Carteira Nacional de Habilitação, the Brazilian driver's license registry number.

  • Parity matrix

Validate

Validates a CNH registry number: 9 digits plus 2 check digits (Resolução CONTRAN nº 886/2021, art. 4º).

  • The function ignores whitespace, dots, hyphens and slashes, in any number and position (000000001/19 and 000000001-19 are read as 00000000119). Any other character makes the value invalid. Until 2.4.0 a slash made the value invalid.
  • Rejects a value whose 11 digits are all the same.
  • Exactly 11 digits are required once the ignored characters are removed.
  • Only a string is read. Any other type returns false.
  • No official text publishes the check-digit weights. Resolução CONTRAN nº 886/2021, art. 4º, and Resolução CONTRAN nº 1.020/2025, art. 10, give only the layout (9 characters and 2 check digits). The algorithm follows a community reference.

Pending decision

The reference (JS) keeps a remainder of 1 in the first check digit as 1, as real registry numbers do (art. 4º § 1º says 0). Python and Erlang use a different (2022) algorithm. See the open decision in docs/findings.md.

Check if a CNH is valid. Spaces, dots, hyphens and slashes are ignored; any other character makes the value invalid.

  • A value whose 11 digits are all the same is rejected, so '11111111111' is invalid.
  • The first check digit keeps a remainder of 1 as 1, as real registry numbers do. Resolução CONTRAN nº 886/2021, art. 4º § 1º, whose remainder of 0 or 1 gives 0, speaks of "O dígito verificador" without naming the number: written in the singular right after the Número do Espelho da CNH (the only number of the article with a single check digit), it reads best as that digit's rule, but it is worded generically and gives no weights, so it is no source for the 2 check digits of the registry number; no official text publishes their weights. Resoluções CONTRAN nº 976/2022, nº 998/2023 and nº 1.006/2024 amend Resolução nº 886/2021, none of them in art. 4º. Resolução CONTRAN nº 1.020/2025, the newer habilitação norm, repeats the layout in its art. 10 ("nove caracteres e dois dígitos verificadores") with no check digit rule and does not revoke the 886 (art. 140).
import { isValidCnh } from '@brazilian-utils/brazilian-utils';

isValidCnh('00000000119'); // true
isValidCnh('000000001-19'); // true (hyphen before the check digits)
isValidCnh('ab00000000119'); // false (letters are rejected)

Source: Resolução CONTRAN nº 886/2021, art. 4º, Resolução CONTRAN nº 1.020/2025, art. 10; weights per siga0984.

Shared test cases (26) and the result in each library cnh.isValid

Format

Formats a CNH number as 000000000-00 (9 digits, hyphen, 2 check digits).

  • options.pad left-pads the value with zeros to 11 digits first.
  • options.obfuscate (default false) hides the first 3 digits and the 2 check digits with *, after padding: ***503064-**. It works with pad and on a partial value. Like pad, it is read for truthiness: a non-boolean such as 1 hides the digits too, and 0 does not.
  • No authority publishes a masking rule for the CNH. The rule is an analogy with the one the Leis de Diretrizes Orçamentárias set for publishing a CPF ("ocultar os três primeiros dígitos e os dois dígitos verificadores", Lei nº 12.309/2010, art. 87, § 5º, repeated up to the LDO 2026, Lei nº 15.321/2025, art. 163), not a published norm.
  • cns.format and passport.format have no obfuscate option.
  • A number is read only when it is a safe non-negative integer. A negative, fractional, non-finite or unsafe number returns an empty string (2.4.0 read the digits of any number, sign and decimal point dropped).
  • A value with no digits (empty, or only letters and symbols) returns an empty string even with options.pad. Until 2.4.0 pad returned the full zero mask (000000000-00).
  • Digits after the 11th are dropped.

Format a CNH.

  • Options (FormatCnhOptions): pad left-pads the value with zeros to the full 11 digits before masking (default false); obfuscate hides the first 3 digits and the 2 check digits. An empty value, or one without digits, gives '' even with pad.
  • obfuscate is applied after pad.
  • No authority publishes a masking rule for the CNH, so obfuscate applies the one the Leis de Diretrizes Orçamentárias set for publishing a CPF ("ocultar os três primeiros dígitos e os dois dígitos verificadores", Lei nº 14.194/2021, art. 149, first set by Lei nº 12.309/2010, art. 87, § 5º), a number with the same structure.
import { formatCnh } from '@brazilian-utils/brazilian-utils';

formatCnh('02650306461'); // 026503064-61
formatCnh('2650306461', { pad: true }); // 026503064-61
formatCnh('02650306461', { obfuscate: true }); // ***503064-**
Shared test cases (28) and the result in each library cnh.format

Parse

Removes CNH formatting and keeps only digits, capped at 11 digits (the digits after the 11th are dropped).

  • A number is read only when it is a safe non-negative integer. A negative, fractional, non-finite or unsafe number returns an empty string (2.4.0 read the digits of any number, sign and decimal point dropped).
  • A value with no digits returns an empty string.

Remove CNH formatting, keep only digits, and cap the result to 11 digits.

import { parseCnh } from '@brazilian-utils/brazilian-utils';

parseCnh('026503064-61'); // '02650306461'
Shared test cases (9) and the result in each library cnh.parse

Generate

Generates a valid random CNH number: 11 digits, unformatted, accepted by cnh.isValid.

  • The 9 base digits are never all the same.

Generate a valid random CNH.

import { generateCnh } from '@brazilian-utils/brazilian-utils';

generateCnh(); // '02650306461'

Source: Lei nº 14.194/2021, art. 149, the CPF masking rule obfuscate borrows, first set by Lei nº 12.309/2010, art. 87, § 5º and repeated by the later LDOs (Lei nº 15.321/2025, art. 163, the one for 2026, repeats it).

Shared test cases (1) and the result in each library cnh.generate

Official sources

Last updated on

On this page