SearchCtrlK

  • ↑↓navigate
  • ↵open
  • escclose

Can’t find it? Contact us

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.

After reading this guide, you will know

  • How to lay out a book as index.md and ch<N>.md files that sdxc pkg epub builds
  • 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:

Terminal
npm add -g @sdxc/kit

Lay 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.jpg

Chapter 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:

my-book/index.md
---
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:

my-book/ch1-arrival.md
## Arrival

The ferry came in at dusk. ![The harbor at dusk](images/harbor.jpg)

### 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

Terminal
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.

Terminal
sdxc pkg epub build essay.md --author "Ana Pérez" --cover cover.jpg

Flags 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:

Terminal
sdxc pkg epub build my-book/ \
  --font fonts/Literata-Regular.woff2 \
  --font fonts/Literata-Italic.woff2 \
  --font fonts/Literata-Bold.woff2

The 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:

my-book/styles.css
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:

Terminal
sdxc pkg epub build my-book/ --allow-remote
✓ Downloading remote files 7/7

Check 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 ##:

Terminal
sdxc pkg epub check my-book/

--json prints the result on stdout for a script, while progress stays on stderr:

Terminal
sdxc pkg epub check my-book/ --json

Set 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:

Terminal
SOURCE_DATE_EPOCH=$(git log -1 --format=%ct) sdxc pkg epub build my-book/ -o dist/the-harbor.epub

Where to go next

Documentation

Can’t find it? Contact us