What is actually inside an EPUB file?
An EPUB is a ZIP archive with rules. Copy one, rename the copy to .zip, unzip it, and you can read every part of it in a text editor. Doing this once makes most ebook troubleshooting obvious.
The five pieces
mimetype — one line: application/epub+zip. Must be the first entry in the archive and must be stored uncompressed. This is how a reader confirms it is an EPUB before parsing anything.
META-INF/container.xml — a pointer. Its only job is to say where the package document lives, because the spec does not fix that location.
The package document (.opf) — the heart of the book. Three sections:
<metadata>— title, author, language, identifier<manifest>— every file in the book, with its media type<spine>— the reading order
Manifest and spine are different things, and confusing them causes real bugs. The manifest is what exists; the spine is what order to read it in. An image is in the manifest and not the spine. A chapter is in both.
The navigation document (nav.xhtml) — the table of contents, as real HTML. EPUB 2 used a separate toc.ncx; well-built EPUB 3 files ship both for compatibility.
The content — your chapters, as XHTML, plus CSS and images.
A real one, unzipped
Here is the actual structure of a small EPUB. This one was produced by the TXT converter on this site from a four-chapter plain-text file — the specimen book we keep in the site’s repository so every example on this blog is reproducible:
$ unzip -l specimen.epub (5,183 bytes total)
251 META-INF/container.xml
364 OEBPS/chapter-001.xhtml
845 OEBPS/chapter-002.xhtml
905 OEBPS/chapter-003.xhtml
618 OEBPS/chapter-004.xhtml
573 OEBPS/chapter-005.xhtml
1314 OEBPS/content.opf
682 OEBPS/nav.xhtml
452 OEBPS/style.css
986 OEBPS/toc.ncx
20 mimetype
mimetype: application/epub+zip
rootfile (from META-INF/container.xml): OEBPS/content.opf
Seven kinds of file, no magic: the mimetype marker, the container pointer,
the package manifest (content.opf), one XHTML file per chapter, a
stylesheet, and both navigation formats. Every section below is about one of
these entries.
Why this is worth knowing
Almost every “corrupt file” message maps onto one of these five pieces: a compressed mimetype, a container pointing at nothing, a manifest listing a file that is not there, a missing nav document, or malformed XHTML.
The Validator checks each of them and names the one that failed — but knowing the structure means the answer actually tells you something.
Manifest and spine, properly
These two are the most commonly confused parts of the package document, and the confusion causes real bugs.
The manifest is an inventory. Every single file in the book must be listed: chapters, stylesheets, images, fonts, the navigation document. If a file is in the archive but not the manifest, strict readers ignore it. If it is in the manifest but not the archive, readers error.
The spine is the reading order, and only for documents that are read. It references manifest ids, not filenames:
<manifest>
<item id="c1" href="chapter-001.xhtml" media-type="application/xhtml+xml"/>
<item id="img1" href="cover.jpg" media-type="image/jpeg"/>
</manifest>
<spine>
<itemref idref="c1"/>
</spine>
The image is in the manifest and not the spine, because you do not “read” it in sequence — a chapter displays it. Getting this backwards produces books that either skip chapters or try to page through images.
Why the mimetype rule is so strict
mimetype must be the first entry in the archive and must be stored uncompressed. This looks arbitrary and is not.
ZIP is a container format with no type field. By mandating that the first entry is an uncompressed file with known contents at a known offset, the spec lets a reader identify an EPUB by reading the first few dozen bytes — no unzipping, no parsing. It is a magic number bolted onto a format that lacks one.
It is also the rule most often broken, because unzipping a book and re-zipping it with a normal archiver compresses everything. The book is intact and unopenable.
The bits nobody mentions
toc.ncx is the EPUB 2 navigation format. EPUB 3 replaced it with nav.xhtml, but well-built books ship both, because older devices only understand the NCX. Shipping both costs a couple of kilobytes.
properties="cover-image" on a manifest item is how EPUB 3 marks the cover. EPUB 2 used a <meta name="cover"> pointing at a manifest id. Readers look for either, which is why a book can have a cover file and still show a blank thumbnail — the file is there but nothing marks it as the cover.
dcterms:modified is required in EPUB 3 and easy to omit. Some validators fail the whole book over it.
Fallback chains let a manifest item declare a substitute for readers that cannot handle its type. Rare, but it is how exotic content degrades gracefully.
Reading a book to debug it
Once you know the five pieces, most failures become a specific place to look:
| Symptom | Look at |
|---|---|
| Will not open at all | mimetype, container.xml |
| Opens, table of contents empty | nav.xhtml / manifest properties="nav" |
| Chapters missing or out of order | <spine> |
| Images broken | manifest hrefs vs actual paths |
| Cover blank in library | cover marking, not the image itself |
| Shows as “Unknown Author” | <metadata> |
The Validator checks each of these and names the specific failure, but knowing the structure is what turns its answer into an action.
Building one by hand
Worth doing once, for the same reason it is worth writing a page of HTML by hand. Make the five pieces, zip them with mimetype first and uncompressed, rename to .epub, and open it in a reader.
It takes twenty minutes and permanently removes the mystery. An EPUB stops being an opaque blob that tools produce and becomes a small website in a zip file — which is exactly what it is, and why the format has outlasted every proprietary alternative aimed at replacing it.
Frequently asked questions
Can I really just rename an EPUB to .zip and open it?
Yes — an EPUB is a ZIP archive with rules. Copy the file first, rename the copy to .zip, unzip it, and every part of the book is readable in a text editor. Doing this once makes most ebook troubleshooting obvious.
What is the difference between the manifest and the spine?
The manifest is what exists; the spine is what order to read it in. Every file in the book — chapters, stylesheets, images, fonts, the navigation document — has to be listed in the manifest. The spine references manifest ids and covers only documents read in sequence, which is why an image belongs in the manifest and not the spine.
Why does re-zipping an EPUB break it?
Because the mimetype entry must be the first in the archive and stored uncompressed, and a normal archiver compresses everything. ZIP has no type field, so the spec bolts a magic number onto it: a reader identifies an EPUB by reading the first few dozen bytes. Re-zip with a standard tool and the book is intact and unopenable.
Why are EPUB chapters XHTML rather than HTML?
XHTML is XML, so parsing is strict — an unclosed tag is a fatal error rather than something the parser guesses around. It is why a chapter can render perfectly in a browser and still break an e-reader.
Does an EPUB 3 file still need toc.ncx?
EPUB 3 replaced the NCX with nav.xhtml, but well-built books ship both because older devices only understand the NCX. Shipping both costs a couple of kilobytes, which is a cheap price for hardware still in daily use.
My book has a cover image but shows a blank thumbnail. Why?
The file is there but nothing marks it as the cover. EPUB 3 marks it with properties="cover-image" on the manifest item; EPUB 2 used a meta name="cover" pointing at a manifest id. Readers look for either, so a book can carry a perfectly good cover that no library ever displays.