A variable-width encoding, by design
UTF-8 encodes any Unicode code point using between 1 and 4 bytes, with the byte count determined by the character's code point value — common characters get fewer bytes, rarer or higher-numbered ones get more:
| Code point range | Bytes used | Example |
|---|---|---|
| U+0000–U+007F (ASCII range) | 1 | A = 0x41 |
| U+0080–U+07FF | 2 | €-adjacent range, some Latin-extended and Greek |
| U+0800–U+FFFF | 3 | € = 0xE2 0x82 0xAC, most CJK characters |
| U+10000–U+10FFFF | 4 | 😀 = 0xF0 0x9F 0x98 0x80 |
Why the leading bits of each byte matter
UTF-8's clever mechanism is embedding byte-count information directly into each byte's leading bits, so a decoder always knows, from any single byte, whether it's looking at the start of a 1/2/3/4-byte sequence or a continuation byte within one — no external length field or lookup needed:
- A byte starting
0xxxxxxxis a complete 1-byte (ASCII-range) character. - A byte starting
110xxxxxbegins a 2-byte sequence. - A byte starting
1110xxxxbegins a 3-byte sequence. - A byte starting
11110xxxbegins a 4-byte sequence. - Any byte starting
10xxxxxxis a continuation byte — part of a multi-byte sequence, never the start of one.
This self-describing structure is exactly what makes UTF-8 resilient to certain kinds of corruption and lets software resynchronize mid-stream if needed, without needing to re-parse from the very beginning.
Why full ASCII compatibility was the killer feature
Because every ASCII character (0–127) encodes as a single byte identical to its ASCII value, any existing ASCII text is already valid UTF-8, byte-for-byte, with no conversion needed at all. This backward compatibility is precisely why UTF-8 could be adopted incrementally across the internet's existing ASCII-based infrastructure — old systems and files kept working unmodified, while new systems gained the ability to represent every Unicode character when needed.
Why UTF-8 dominates the web specifically
Combining full Unicode coverage with ASCII backward-compatibility and reasonable compactness for Latin-script-heavy content (the majority of existing web text at the time of adoption) made UTF-8 the practical winner over alternatives like UTF-16 for general web use — see UTF-8 vs UTF-16 for where UTF-16 remains the better choice instead.
Common mistakes
- Assuming every character takes the same number of bytes in UTF-8. It's variable-width by design — English text is mostly 1 byte per character, but non-Latin scripts and emoji take more.
- Truncating a UTF-8 string by raw byte count without checking for continuation bytes. Cutting in the middle of a multi-byte character produces invalid, undecodable bytes at the cut point.
- Confusing UTF-8 with Unicode itself. UTF-8 is one specific encoding of Unicode's character set — not synonymous with it (see What is Unicode).
FAQ
How many bytes does a UTF-8 character take?
Between 1 and 4, depending on the character's Unicode code point — common Latin characters take 1 byte; most other scripts and symbols take 2–4.
Why is every ASCII text file also valid UTF-8?
Because UTF-8 encodes code points 0–127 as a single byte identical to the ASCII value — no conversion is needed for pure ASCII content.
How does a UTF-8 decoder know how many bytes a character uses?
The leading bits of the first byte in a sequence directly encode the total byte count, letting a decoder determine this without any external length information.
Explore character encoding behavior with the ASCII Generator — entirely in your browser.