Unicode Normalization: NFC vs NFD

Unicode can represent the same visible text with different code-point sequences. The character “é” may be one precomposed code point or the letter “e” followed by a combining accent. Binary comparison treats those sequences as different until they are normalized.

Last updated: September 26, 2026.

const composed = "café";
const decomposed = "café";

console.log(composed === decomposed); // false
console.log(composed.normalize("NFC") === decomposed.normalize("NFC")); // true

const key = decomposed.normalize("NFC");

NFC performs canonical decomposition followed by composition and is a common storage and comparison choice for general text. NFD keeps canonically decomposed sequences.

Choose the form for the job

Use NFC for ordinary application text when you want canonically equivalent input to share one representation. Some filesystems and text-processing systems favor decomposed forms, so boundaries may produce NFD. Normalize both stored values and lookup input to the same form when exact comparisons matter.

NFKC and NFKD also apply compatibility mappings and can erase distinctions such as presentation forms. They may be useful for restricted identifiers, but they are not a general replacement for NFC.

Normalize at controlled boundaries

Normalize after decoding bytes into Unicode and before generating comparison keys. Do not confuse normalization with character encoding: converting Windows-1252 bytes to UTF-8 solves a different problem. Normalization also does not provide case folding, accent-insensitive search, or locale-aware sorting.

The Unicode Consortium’s current Normalization Forms specification defines NFC, NFD, NFKC, and NFKD and guarantees stable behavior.

Test databases and files

  • Compare code points as well as visual output.
  • Test unique constraints with composed and decomposed forms.
  • Normalize filenames before duplicate checks when platforms differ.
  • Keep the original display text if a normalized search key is sufficient.

If visible text contains sequences such as “é”, that is mojibake rather than normalization. Use the garbled-text diagnostic workflow.

Related Web Cheat Sheet guides

Sergey Kornilov

Sergey Kornilov