What's the difference between UTF-8 and UTF-8 with BOM?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
UTF-8 and UTF-8 with BOM are the same character encoding. The only difference is that UTF-8 with BOM prepends three invisible bytes (EF BB BF) at the very start of the file. This Byte Order Mark acts as a signature telling editors "this file is UTF-8," but since UTF-8 has no byte-order ambiguity, the BOM is unnecessary and frequently causes bugs in Unix tools, web servers, and programming languages.
What Is UTF-8?
UTF-8 is a variable-width encoding that can represent every Unicode code point using one to four bytes. It is backward-compatible with ASCII: any valid ASCII file is also valid UTF-8.
| Code point range | Bytes used | Example character |
| U+0000 to U+007F | 1 byte | A (0x41) |
| U+0080 to U+07FF | 2 bytes | e (0xC3 0xA9) |
| U+0800 to U+FFFF | 3 bytes | $ (0xE2 0x82 0xAC) |
| U+10000 to U+10FFFF | 4 bytes | (0xF0 0x9F 0x98 0x80) |
UTF-8 is the dominant encoding on the web. Over 98% of all websites use it.
What Is the BOM?
BOM stands for Byte Order Mark. It is the Unicode code point U+FEFF. For encodings like UTF-16 and UTF-32 where byte order matters, the BOM serves a real purpose: it tells the decoder whether the file is big-endian or little-endian.
| Encoding | BOM bytes | Purpose |
| UTF-8 | EF BB BF | Signature only (no byte-order issue) |
| UTF-16 BE | FE FF | Indicates big-endian byte order |
| UTF-16 LE | FF FE | Indicates little-endian byte order |
| UTF-32 BE | 00 00 FE FF | Indicates big-endian byte order |
| UTF-32 LE | FF FE 00 00 | Indicates little-endian byte order |
UTF-8 does not have a byte-order issue because it reads one byte at a time. The BOM in UTF-8 is purely a marker that says "this file is UTF-8." Most modern tools already detect UTF-8 without it.
Side-by-Side Comparison
Let's see how the string Hello is stored in both formats.
UTF-8 (no BOM):
UTF-8 with BOM:
The content is identical. The only difference is the three leading bytes.
Verifying with code
Python:
Command line (Linux/macOS):
PowerShell (Windows):
When the BOM Causes Problems
The BOM is three invisible bytes. Any tool that does not expect them will treat them as data, leading to subtle and frustrating bugs.
PHP and web output
The BOM bytes constitute output, so PHP thinks headers have already been sent.
Bash scripts
JSON parsing
CSV files and Excel
Ironically, Excel on Windows sometimes requires a BOM to correctly display UTF-8 CSV files. Without it, Excel may default to a local encoding (like Windows-1252) and corrupt accented characters. This is one of the few legitimate reasons to include a BOM.
String comparison and concatenation
Full Comparison Table
| Aspect | UTF-8 | UTF-8 with BOM |
| Leading bytes | None | EF BB BF |
| File size overhead | 0 bytes | 3 bytes |
| Web (HTML, CSS, JS) | Recommended | Discouraged by W3C |
| Unix/Linux tools | Fully compatible | May cause bugs |
| PHP | Works | Breaks header() and sessions |
Python json.load | Works | Fails without utf-8-sig |
| Bash/shell scripts | Works | Breaks shebang line |
| Excel CSV import | May misdetect encoding | Displays correctly |
| Windows Notepad (old) | May default to ANSI | Detects as UTF-8 |
| Visual Studio | Works | Works (strips BOM on read) |
| Git diffs | Clean | BOM shows as diff noise |
When to Use Each
Use UTF-8 (no BOM) for:
- Web files: HTML, CSS, JavaScript, JSON, XML
- Source code in any language
- Unix/Linux configuration files
- API responses
- Anything stored in version control
Use UTF-8 with BOM for:
- CSV files that must open correctly in Excel on Windows
- Files consumed by legacy Windows applications that rely on the BOM for encoding detection
- Interoperability with older Microsoft tools (pre-2019 Notepad, older Visual Studio versions)
How to Convert Between Formats
In VS Code
- Click the encoding label in the bottom status bar (e.g., "UTF-8").
- Select Save with Encoding.
- Choose UTF-8 or UTF-8 with BOM.
In Notepad++
- Go to Encoding in the menu bar.
- Select Convert to UTF-8 (removes BOM) or Convert to UTF-8-BOM.
Programmatically
Python (remove BOM):
Node.js (remove BOM):
Common Pitfalls
- Invisible bugs. The BOM is invisible in most editors. If a file "looks right" but behaves wrong, check for a BOM with a hex editor or
hexdump. - Git BOM noise. A BOM can show up as a diff change when collaborators use different editors. Add an
.editorconfigwithcharset = utf-8to standardize. - Windows Notepad legacy. Older versions of Windows Notepad saved UTF-8 with BOM by default. Since Windows 10 version 1903, Notepad defaults to UTF-8 without BOM.
- Double BOM. Concatenating two BOM files produces a BOM in the middle of the output, which appears as the invisible character
U+FEFFin your data. - Encoding detection heuristics. Some tools use the BOM to decide encoding. If you remove the BOM from a file that a legacy tool depends on, the tool may fall back to ASCII or a local codepage.
Summary
- UTF-8 and UTF-8 with BOM are the same encoding. The BOM is just three extra bytes (
EF BB BF) at the start of the file. - UTF-8 has no byte-order ambiguity, so the BOM serves no technical purpose beyond being a file signature.
- The BOM causes real bugs in PHP, Bash, JSON parsers, and Unix tools. Avoid it unless you have a specific reason.
- The main legitimate use case for BOM is CSV files opened in Excel on Windows.
- Use
utf-8-sigin Python to read files that may or may not have a BOM. - Set your editor to save as UTF-8 without BOM by default. Standardize with
.editorconfig.

