What Is a File Magic Number? Format Detection Explained
Published April 24, 2026 · 6 min read
How Does the OS Know What a File Is?
Rename a PNG to .txt. macOS Quick Look still previews it as an image. Run file renamed.txt on Linux — the output still reads PNG image data. The filename changed, but the format didn't. Why?
Because many format detectors inspect a sequence of bytes in the file itself — called a magic number (also known as a file signature or file header) — instead of trusting the filename alone.
Filename extensions still affect how operating systems associate and open files. Tools such as the Unix <code>file</code> command and some browser or server sniffing paths can additionally inspect known byte signatures, but they do not all apply identical rules.
What Is a Magic Number?
Every file format reserves a fixed sequence of bytes at the very beginning of the file to declare its type. These are called magic numbers (also known as file signatures or file headers).
Think of it like a passport: border control doesn't ask your name — they open to page one and confirm your nationality from the fixed format. A magic number is a file's "page one." No matter what the file is named, those first bytes tell you the truth.
This is how the Unix file command works: it maintains a magic database of byte patterns and compares the file contents with those patterns. That is useful evidence of the underlying format, but the filename, declared MIME type, and container metadata can still affect how a particular tool handles the file.
Magic Number Quick-Reference Table
Common format signatures you'll encounter in practice:
| Format | Magic Bytes (Hex) | ASCII | Notes |
|---|---|---|---|
| PNG | 89 50 4E 47 0D 0A 1A 0A | ‰PNG.... | 8 bytes, one of the most recognizable |
| JPEG | FF D8 FF | — | 3 bytes; 3rd byte varies by subtype |
| GIF | 47 49 46 38 | GIF8 | Followed by 37 (GIF87a) or 39 (GIF89a) |
| 25 50 44 46 | %PDF | Followed by version, e.g. -1.7 | |
| WebP | 52 49 46 46 … 57 45 42 50 | RIFF…WEBP | RIFF container; check bytes 8–11 |
| WAV | 52 49 46 46 … 57 41 56 45 | RIFF…WAVE | RIFF container; subtype is WAVE |
| MP3 | 49 44 33 / FF Fx | ID3 / sync | With ID3 tag: starts with ID3; without tag: sync word FF Ex or FF Fx |
| FLAC | 66 4C 61 43 | fLaC | Lossless audio, unambiguous signature |
| MP4 / MOV / M4A | 00 00 00 xx 66 74 79 70 | ....ftyp | ftyp container; check brand at bytes 8–11 |
| WebM | 1A 45 DF A3 | — | EBML container header |
| OGG | 4F 67 67 53 | OggS | OGG audio/video container |
| BMP | 42 4D | BM | Windows bitmap |
The Gotcha: Four Bytes Aren't Always Enough
Two container families share common prefixes across completely different media types. Stopping at byte 4 will give you the wrong answer.
RIFF Container (WebP / WAV / AVI)
WebP, WAV, and AVI all start with RIFF (52 49 46 46). The actual subtype is at bytes 8–11:
ftyp Container (MP4 / MOV / M4A)
MP4, MOV, and M4A start with a variable 4-byte box size, then ftyp at bytes 4–7. The brand code at bytes 8–11 determines the actual format:
Brand codes to know: isom / iso2 / avc1 = MP4, M4A = M4A (Apple audio), qt = QuickTime MOV.
Try It: The file Command Reads Magic Numbers Directly
On macOS and Linux, the file command identifies formats by reading magic numbers — not by looking at the filename:
# macOS / Linux
$ file -b photo.png
PNG image data, 617 x 875, 8-bit/color RGBA, non-interlaced
$ file -b photo.txt # extension changed to .txt
PNG image data, 617 x 875, 8-bit/color RGBA, non-interlaced file is a built-in tool on macOS and Linux. Windows has no native equivalent.
If you need to implement the same detection in code, the core logic is just a few lines of JavaScript:
// Read the first 18 bytes of a Base64 string for format detection
// (every 4 Base64 chars = 3 bytes)
const b64 = "iVBORw0KGgoAAAANSUhEUgAA...";
const bin = atob(b64.slice(0, 24));
const hex = [...bin]
.map(c => c.charCodeAt(0).toString(16).padStart(2, "0"))
.join(" ");
console.log(hex);
// → 89 50 4e 47 0d 0a 1a 0a ... (PNG) Cross-reference the table: 89 50 4e 47 → PNG, ff d8 ff → JPEG, 25 50 44 46 → PDF.
Summary
Magic bytes are strong evidence about the underlying binary format, but they are not a complete universal type system. Read the relevant bytes, compare them with a documented signature, and account for MIME declarations, container metadata, and the rules of the tool consuming the file.
Renaming a file does not change its bytes, so content-based detectors can still recognize the original format; filename-based associations may behave differently.
Related Article
How to Debug Base64 Images in JSON API Responses →ViewJSON applies magic number detection to every string in your JSON — Base64 images, audio, and video render as inline previews automatically.
Try It Now
Paste any JSON with Base64 content — ViewJSON auto-detects the format and renders images, audio, and video inline. No manual decoding.
Open ViewJSON →