UTF-8 vs UTF-16
UTF-8 and UTF-16 encode the same Unicode characters using different byte layouts. UTF-8 uses one to four bytes per character and is byte-identical to ASCII for the first 128, which is why it dominates the web. UTF-16 uses two or four and is what JavaScript, Java and Windows use internally. Always choose UTF-8 for files and network traffic.
Unicode Escape and Unescape
Convert characters to \uXXXX escapes and back.
Unicode assigns a number to every character. An encoding decides how those numbers become bytes, and UTF-8 and UTF-16 are two answers to that question — not two different character sets. Any text expressible in one is expressible in the other.
The choice matters for two reasons: size on disk and over the wire, and the surprising ways string length behaves in languages that use UTF-16 internally.
Byte sizes
- ASCII (A–Z, digits, punctuation): 1 byte in UTF-8, 2 in UTF-16.
- Latin with accents, Greek, Cyrillic, Hebrew, Arabic: 2 bytes in both.
- Chinese, Japanese, Korean: 3 bytes in UTF-8, 2 in UTF-16.
- Emoji and other astral characters: 4 bytes in both.
Why UTF-8 won the web
Backward compatibility. Any ASCII file is already valid UTF-8, byte for byte, so decades of existing text and protocols kept working with no migration. UTF-8 also has no byte-order ambiguity — UTF-16 comes in big-endian and little-endian forms and needs a byte-order mark to tell them apart — and it never produces a zero byte inside a character, which would terminate a C string early. Around 98% of web pages now use it.
Surrogate pairs, and why lengths disagree
UTF-16 represents characters above U+FFFF as two 16-bit units called a surrogate pair. Languages that expose strings as UTF-16 units — JavaScript, Java, C# — therefore report a length of 2 for a single emoji. In Python 3 or Go, the same character counts as one. Neither is wrong; they are counting different things. It is why "😀".length is 2 in JavaScript, why slicing a string can split a character in half, and why iterating by code point rather than by index matters.
Where each is used
UTF-8 for files, HTTP, JSON, XML, databases, source code — anything stored or transmitted. UTF-16 mostly appears as an in-memory representation: JavaScript strings, Java and C# strings, the Windows API, and some older file formats. You rarely choose UTF-16 deliberately; you encounter it because a platform uses it internally.
Practical advice
Declare UTF-8 everywhere — HTTP headers, HTML meta tags, database and connection charsets, and the encoding argument wherever files are read or written. Almost all garbled text comes from one link in that chain disagreeing with the others. When counting or slicing strings, count what you actually mean: bytes for storage limits, code points for characters, and grapheme clusters for what a person would call a character.
Frequently asked questions
Which should I use for my files?
Is UTF-8 always smaller than UTF-16?
Why does JavaScript say my emoji has a length of 2?
What is a byte-order mark and do I need one?
Can UTF-8 represent every character UTF-16 can?
Tools used in this guide
All tools →- Unicode Escape and Unescape Convert characters to \uXXXX escapes and back. In your browser
- Character Counter Count characters with and without spaces, live as you type. In your browser
- Text to Binary Converter Convert text to binary, hex, octal or decimal and back. In your browser
- Text Cleaner Strip formatting, smart quotes and invisible characters. In your browser
- Base64 Encoder and Decoder Encode text to Base64 or decode it back, including URL-safe. In your browser
Related guides
All guides →Last reviewed .