# What Is a Byte Order Mark (BOM)? — UTF-8 BOM, Excel, and What It Breaks

Canonical: https://commareports.com/glossary/byte-order-mark
Published: 2026-10-13

> A byte order mark is the invisible U+FEFF character at the start of a text file. Why Excel needs it to read UTF-8 CSVs, why JSON parsers and shell scripts choke on it, and how to add or remove one.

# Byte order mark (BOM)

**A byte order mark is the Unicode character U+FEFF placed at the very
start of a text file to signal its encoding.** It is invisible in every
editor that understands it, and a stray garbage character — `ï»¿` — in
every program that doesn't.

| Encoding | BOM bytes  |
| -------- | ---------- |
| UTF-8    | `EF BB BF` |
| UTF-16LE | `FF FE`    |
| UTF-16BE | `FE FF`    |

In UTF-16 the BOM does real work: it says which byte comes first. UTF-8
has no byte order, so there it is only an encoding signature — and the
Unicode standard neither requires nor recommends it.

## Where you want one: CSV for Excel

Double-click a UTF-8 CSV without a BOM on Windows and Excel decodes it in
the legacy system code page. `Zoë Müller` becomes `ZoÃ« MÃ¼ller`. Add the
three BOM bytes and the same file opens correctly — which is why
[JSON to CSV](/tools/json-to-csv) writes one by default, and why
[a CSV that opens wrong in Excel](/fix/csv-opens-wrong-in-excel) is so
often fixed by re-saving as "CSV UTF-8".

## Where it breaks things

- **Shell scripts.** The kernel looks for `#!` in the first two bytes. A
  BOM in front means the shebang is ignored.
- **JSON.** RFC 8259 says senders must not add one. JavaScript's
  `JSON.parse` throws on a leading `﻿`; many other parsers tolerate it.
- **PHP and templates.** The BOM is output before `<?php`, so headers have
  already been sent.
- **CSV readers.** Python's `csv` with `encoding="utf-8"` keeps it, so the
  first header is `"﻿id"` and `row["id"]` raises `KeyError`. Use
  `utf-8-sig`.

## In HTML

Browsers check for a BOM before anything else, and the HTML standard lets
it override both the `Content-Type` charset and `<meta charset>`. A
report whose `<meta>` says one encoding and whose bytes start with a BOM
for another will render by the BOM. If a published report shows `Ã©`
where `é` should be, check the first three bytes before the meta tag.

## Adding and removing it

- **Remove:** "Save with encoding → UTF-8" (not "UTF-8 with BOM") in VS
  Code; `sed -i '1s/^\xEF\xBB\xBF//' file` with GNU sed; `utf-8-sig` when
  reading in Python.
- **Add:** prepend `﻿` to the string before writing the file, or
  choose "CSV UTF-8" in Excel's Save As.
- **Check:** `head -c3 file | xxd` prints `efbb bf` when one is there.

## Try it

Comma is free — unlimited reports, unlimited commenters, unlimited
revision history.

**[Convert JSON to an Excel-ready CSV →](/tools/json-to-csv)**

### Related

- [CSV injection](/glossary/csv-injection) · [MIME type](/glossary/mime-type)
- [CSV opens wrong in Excel](/fix/csv-opens-wrong-in-excel) · [CSV to JSON](/tools/csv-to-json)
- [Glossary](/glossary)
