Blog
3 min read

What Is UTF-8? Character Encoding and Garbled Text (Mojibake) Explained

UTF-8 is the character encoding that lets computers store every language and emoji as bytes — and it's the default almost everywhere now. How encoding works, why you see garbled text like ’ or é, and how to fix it in HTML, databases, CSV files and code.

UTF-8 is the most common way computers turn text into bytes and back again. It can represent every character in Unicode — English letters, accented letters, Arabic, Chinese, emoji — and it's the default for the web, JSON, Linux, and most modern databases.

You usually only notice it when it goes wrong, and your app shows café instead of café, or it’s instead of it's.

Characters, code points and bytes

Computers only store numbers. Text needs two agreements:

  1. A character set that gives every character a number. Unicode is the universal one: A is 65, é is 233, 😀 is 128512. These numbers are called code points.
  2. An encoding that says how to write those numbers as bytes. UTF-8 is one encoding of Unicode.

UTF-8's clever trick is that it uses 1 byte for ASCII characters, including English letters, digits and basic punctuation (so old ASCII text is valid UTF-8 unchanged), and 2 to 4 bytes for non-ASCII characters.

Character Bytes in UTF-8
A 1
é 2
€ 3
😀 4

Why text gets garbled ("mojibake")

Garbled text happens when bytes are written in one encoding and read in another. The classic case: text saved as UTF-8 but read as Windows-1252 (which differs from ISO-8859-1, also called Latin-1):

Should be Shows as
é é
’ (curly apostrophe) ’
“ (opening curly quote) “
😀 😀

If you see à and †patterns, something likely read UTF-8 bytes as Windows-1252 or another legacy encoding. The data itself is often fine — the reader is wrong.

How to fix it, by where it shows up

Web pages: declare UTF-8 at the top of your HTML and make sure the server sends it:

<meta charset="utf-8">

The Content-Type: text/html; charset=utf-8 header should agree. (HTTP Headers Explained)

Databases: Postgres databases are normally created with UTF-8 encoding — check with SHOW server_encoding;. In MySQL, use utf8mb4, not the older utf8, which can't store emoji. (Postgres vs MySQL)

CSV files from Excel: Excel may save CSVs in a legacy encoding, or need a "BOM" to open UTF-8 CSVs correctly. Use "CSV UTF-8" when saving, and when importing, tell your tool the file is UTF-8. (Import a CSV Into Postgres)

Code: be explicit when reading files:

open('data.txt', encoding='utf-8')
fs.readFileSync('data.txt', 'utf8')

Text that was double-encoded

Sometimes text was decoded wrongly and saved that way — the garbage is now in your database. Fixing it means reversing the specific mistake: encode back using the encoding that was wrongly used (Windows-1252 for the examples above), then decode those bytes as UTF-8. This only works if no bytes were lost or replaced. Test on a copy first, and back up before running anything over real data. (Backups for Beginners)

The summary

  • Unicode numbers every character; UTF-8 turns those numbers into 1–4 bytes.
  • Garbled text like ’ means UTF-8 was read as a different encoding.
  • Use UTF-8 everywhere: HTML meta tag, headers, database (utf8mb4 in MySQL), file reads.

EasySpawn runs your app and its Postgres database together on one server, set up with UTF-8 from the start, with Claude Code there to untangle the odd file that isn't. See how it works or join the waitlist.

Related: What Is Base64? · How to Read an Error Message · What Is JSON? · Debugging for Beginners

Keep reading