Comparison

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.

Open the tool

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?
UTF-8, essentially without exception. It is the web standard, it is ASCII-compatible, it has no byte-order ambiguity, and it is smaller for the Latin text that dominates markup and code even in documents written in other languages.
Is UTF-8 always smaller than UTF-16?
No. For Chinese, Japanese and Korean text UTF-8 uses three bytes per character against UTF-16's two. But real documents carry markup, tags and code in ASCII, so UTF-8 usually wins overall even there.
Why does JavaScript say my emoji has a length of 2?
JavaScript strings are UTF-16, and characters above U+FFFF need a surrogate pair — two 16-bit units. The length property counts units, not characters. Spreading the string with [...str] or using Intl.Segmenter counts characters properly.
What is a byte-order mark and do I need one?
A marker at the start of a file indicating byte order. UTF-16 genuinely needs it because it has two byte orders. UTF-8 does not, and a BOM on a UTF-8 file causes more problems than it solves — it can break JSON parsing and corrupt the first CSV column header.
Can UTF-8 represent every character UTF-16 can?
Yes. Both encode the whole of Unicode, so conversion between them is lossless in either direction. They differ only in how the numbers become bytes.

Tools used in this guide

All tools →
All guides →

Last reviewed .