Driver's license (CNH)
Carteira Nacional de Habilitação, the Brazilian driver's license registry number.
Validate
- JavaScript library
- Python library5 cases fail
- Go library3 cases fail
- Ruby library3 cases fail
- Rust library3 cases fail
- .NET library3 cases fail
- Erlang library5 cases fail
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/19and000000001-19are read as00000000119). 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.
| Parameter | Type | Required |
|---|---|---|
value | string | yes |
| returns | boolean |
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 gives0, 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/javascriptTry it with JavaScript isValidCnh
Shared test cases (26) and the result in each library cnh.isValid
Format
- JavaScript library
- Python library
- Go library
- Ruby library11 cases fail
- Rust library
- .NET library1 case fails
- Erlang library
Formats a CNH number as 000000000-00 (9 digits, hyphen, 2 check digits).
options.padleft-pads the value with zeros to 11 digits first.options.obfuscate(defaultfalse) hides the first 3 digits and the 2 check digits with*, after padding:***503064-**. It works withpadand on a partial value. Likepad, it is read for truthiness: a non-boolean such as1hides the digits too, and0does 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.formatandpassport.formathave noobfuscateoption.- 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.0padreturned the full zero mask (000000000-00). - Digits after the 11th are dropped.
| Parameter | Type | Required |
|---|---|---|
value | string | number | yes |
options | FormatCnhOptions | no |
options.pad | boolean | no |
options.obfuscate | boolean | no |
| returns | string |
Format a CNH.
- Options (
FormatCnhOptions):padleft-pads the value with zeros to the full 11 digits before masking (defaultfalse);obfuscatehides the first 3 digits and the 2 check digits. An empty value, or one without digits, gives''even withpad. obfuscateis applied afterpad.- No authority publishes a masking rule for the CNH, so
obfuscateapplies 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-**Try it with JavaScript formatCnh
Shared test cases (28) and the result in each library cnh.format
Parse
- JavaScript library
- Python library
- Go library
- Ruby library2 cases fail
- Rust library
- .NET library1 case fails
- Erlang library
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.
| Parameter | Type | Required |
|---|---|---|
value | string | number | yes |
| returns | 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'Try it with JavaScript parseCnh
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.
| Parameter | Type | Required |
|---|---|---|
| returns | string |
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).
Try it with JavaScript generateCnh
Shared test cases (1) and the result in each library cnh.generate
Official sources
Last updated on
