Write a book in Markdown
Keep a book as a folder of Markdown chapters and build it into an EPUB from the terminal with sdxc pkg epub, with a title page, embedded fonts and images, checked in CI.
Last updated by
After reading this guide, you will know
- How to lay out a book as
index.mdandch<N>.mdfiles thatsdxc pkg epubbuilds - How to add a cover, fonts, a stylesheet and images, including ones from the web
- How to check the book in CI and build it the same way every time
A book kept as Markdown files diffs, reviews and versions like code. sdxc pkg epub turns those
files into an EPUB that e-readers, phone reading apps and Send to Kindle open, without any code
of your own. It runs the command line @sdxc/epub ships, which refuses at build time
what epubcheck would reject.
Install sdxc once, as The sdxc command shows:
npm add -g @sdxc/kitLay out the book
A book is a folder. index.md holds the details about the book and its title, and each chapter
file holds chapters:
my-book/
├── index.md
├── ch1-arrival.md
├── ch2.md
├── ch10.md
├── styles.css
└── images/
└── harbor.jpgChapter files are named ch followed by a number, with an optional -slug. They are read in
number order, so ch10.md comes after ch9.md, not after ch1.md.
index.md starts with frontmatter, then the # title. Any text after the title is placed on its
own page before the first chapter, which suits a dedication or an epigraph:
---
author: Ana Pérez
language: en
description: Stories from a harbor town.
cover: images/harbor.jpg
---
# The Harbor
For my mother, who read to me.The title gets a page to itself, set large and centered like a cover, with the authors below it.
Every ## heading in a chapter file starts a chapter, and ### headings become entries nested
under it in the table of contents:
## Arrival
The ferry came in at dusk. 
### The Inn
She took the room above the bar.[^1]
[^1]: The inn closed in 1998.A footnote is kept with the chapter that cites it. Links work across chapters too: [back to the inn](#the-inn) and [next](ch2.md) point at the right page in the book.
Build it
sdxc pkg epub build my-book/Each step prints a line to stderr with its progress, and the book is written beside the folder as
my-book.epub:
✓ Reading my-book 5/5
✓ Reading images, stylesheets and fonts 1/1
✓ Wrote my-book.epub: 5 pages, 412.3 KB-o dist/the-harbor.epub writes it somewhere else. A short piece doesn't need a folder: pass a
single file, and its ## headings become the chapters. A file with no ## heading becomes one
chapter.
sdxc pkg epub build essay.md --author "Ana Pérez" --cover cover.jpgFlags such as --title, --author, --language and --cover override the frontmatter.
Add fonts and a stylesheet
--font embeds a font file. The first font sets the body text, and the rest of the same family
add its italic and bold:
sdxc pkg epub build my-book/ \
--font fonts/Literata-Regular.woff2 \
--font fonts/Literata-Italic.woff2 \
--font fonts/Literata-Bold.woff2The family, weight and style come from each font file, so you write no @font-face rules. A font
whose license forbids embedding is refused. The book also tells Apple Books to use the fonts,
which it otherwise ignores.
styles.css in the folder applies after the built-in reading stylesheet, so it only needs your
changes. A font it loads with url() is embedded too:
h2 {
font-variant: small-caps;
}--style adds a stylesheet from anywhere else, and --no-default-style leaves out the built-in
one, centered title page included.
Use images from the web
An image that loads from a URL fails the build, since a book must carry its own files:
https://example.com/map.png: remote-resource "ch3.md" loads "https://example.com/map.png" from the web; download it into the book or allow remote files
Pass --allow-remote to download it into the book, at your own risk.--allow-remote downloads each image into the book, at most 20 MB and 30 seconds per file. It
fetches every URL the book names, so use it only on books whose links you trust. The downloads get
a progress line of their own:
sdxc pkg epub build my-book/ --allow-remote✓ Downloading remote files 7/7Check it in CI
check runs the whole build and writes nothing. It exits 1 and names the file to fix when the book
has a problem, such as a missing image, malformed markup, a broken link or a chapter file with text
before its first ##:
sdxc pkg epub check my-book/--json prints the result on stdout for a script, while progress stays on stderr:
sdxc pkg epub check my-book/ --jsonSet SOURCE_DATE_EPOCH when you build a release, and two builds of the same files come out byte
for byte equal. The identifier e-readers recognize the book by is derived from its title and
authors, so a new build replaces the old one in a reader's library instead of appearing beside it:
SOURCE_DATE_EPOCH=$(git log -1 --format=%ct) sdxc pkg epub build my-book/ -o dist/the-harbor.epubWhere to go next
Offer posts as EPUB ebooks builds books from inside an app, with
fromMarkdownfrom@sdxc/epub/markdownreading the same layout.Use a package from the terminal covers the conventions every package command line shares.
@sdxc/epublists every error code a build can fail with.