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.

ParameterTypeRequired
valuestringyes
returnsboolean

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.

Code: brazilian-utils/javascript
Try it with JavaScript isValidCnh
The inputs start with the first shared case. Change one to see the new result.

Runs @brazilian-utils/brazilian-utils 2.5.0 in your browser.

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.
ParameterTypeRequired
valuestring | numberyes
optionsFormatCnhOptionsno
options.padbooleanno
options.obfuscatebooleanno
returnsstring

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-**
Code: brazilian-utils/javascript
Try it with JavaScript formatCnh
The inputs start with the first shared case. Change one to see the new result.

Runs @brazilian-utils/brazilian-utils 2.5.0 in your browser.

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.
ParameterTypeRequired
valuestring | numberyes
returnsstring

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

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

parseCnh('026503064-61'); // '02650306461'
Code: brazilian-utils/javascript
Try it with JavaScript parseCnh
The inputs start with the first shared case. Change one to see the new result.

Runs @brazilian-utils/brazilian-utils 2.5.0 in your browser.

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.
ParameterTypeRequired
returnsstring

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).

Code: brazilian-utils/javascript
Try it with JavaScript generateCnh
The inputs start with the first shared case. Change one to see the new result.

Runs @brazilian-utils/brazilian-utils 2.5.0 in your browser.

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

Official sources

Last updated on

On this page