md-to-epub
v1.1.1
Published
A TypeScript CLI tool to convert markdown files to EPUB format
Maintainers
Readme
md-to-epub
A TypeScript CLI tool to convert markdown files to EPUB format for e-readers. Supports single file conversion and bulk processing with extensive markdown features including images, footnotes, tables, code blocks, and more.
Features
- ✅ Comprehensive Markdown Support: Tables, code blocks, blockquotes, lists, and more
- 📷 Image Embedding: Automatically embeds images referenced in markdown
- 📝 Footnotes: Full support for markdown footnotes
- 📚 Bulk Conversion: Convert entire directories of markdown files
- ⚙️ Configuration Files: Use
.md-to-epubrcfiles for project-wide settings - 🎨 Styled Output: Professional EPUB formatting with customizable CSS
- 🔧 CLI & Programmatic API: Use as a command-line tool or import into your projects
Installation
Global Installation
npm install -g md-to-epubLocal Installation
npm install md-to-epubUsage
Command Line
Basic Usage
Convert a single markdown file:
md-to-epub input.mdThis will create output/input.epub using default settings.
Specify Output Path
md-to-epub input.md -o mybook.epubSet Metadata
md-to-epub input.md \
--author "Jane Doe" \
--title "My Great Book" \
--language en \
--publisher "My Publisher"Include Cover Image
md-to-epub input.md --cover ./cover.jpgBulk Conversion
Convert all markdown files in a directory:
md-to-epub ./content-folderRecursively process subdirectories:
md-to-epub ./content-folder --recursiveSpecify output directory for bulk conversion:
md-to-epub ./content-folder --output-dir ./ebooksMulti-Chapter Books
Combine multiple markdown files into a single EPUB with chapters:
md-to-epub chapter1.md chapter2.md chapter3.md --chapters -o book.epubCombine all markdown files in a directory as chapters:
md-to-epub ./chapters-folder --chapters -o complete-book.epubRecursively find and combine chapters:
md-to-epub ./book-project --chapters --recursive -o complete-book.epubConfiguration File
Create a .md-to-epubrc file in your project directory or home directory to set default options:
JSON format:
{
"author": "Jane Doe",
"language": "en",
"publisher": "My Publishing House",
"outputDir": "./ebooks",
"rights": "Copyright © 2025 Jane Doe"
}INI format:
author = Jane Doe
language = en
publisher = My Publishing House
outputDir = ./ebooks
rights = Copyright © 2025 Jane DoeThe configuration file will be automatically loaded from:
- Current directory (
.md-to-epubrc) - Parent directories (searching upward)
- Home directory (
~/.md-to-epubrc)
CLI options will override configuration file settings.
Programmatic Usage
import { convertMarkdownToEpub, convertMarkdownFilesToChapters, loadConfig } from 'md-to-epub';
// Convert single file
await convertMarkdownToEpub({
inputPath: './content/chapter1.md',
outputPath: './output/chapter1.epub',
config: {
author: 'Jane Doe',
title: 'Chapter 1',
language: 'en',
},
});
// Convert multiple files to chapters in single EPUB
await convertMarkdownFilesToChapters(
['./ch1.md', './ch2.md', './ch3.md'],
'./output/book.epub',
{
author: 'Jane Doe',
title: 'Complete Book',
language: 'en',
}
);
// Use configuration file
const config = loadConfig({ author: 'Override Author' });
await convertMarkdownToEpub({
inputPath: './content/chapter1.md',
config,
});
// Bulk conversion (separate EPUBs)
import { convertDirectory } from 'md-to-epub';
const outputFiles = await convertDirectory(
'./content',
{ author: 'Jane Doe', language: 'en' },
true // recursive
);
console.log('Created:', outputFiles);CLI Options
| Option | Description | Default |
|--------|-------------|---------|
| <input...> | Input markdown file(s) or directory | (required) |
| -o, --output <path> | Output EPUB file path | output/<filename>.epub |
| -d, --output-dir <dir> | Output directory for bulk conversion | ./output |
| -r, --recursive | Process directories recursively | false |
| --chapters | Combine multiple files as chapters in single EPUB | false |
| -a, --author <name> | Book author name | Unknown Author |
| -t, --title <title> | Book title (overrides H1 from markdown) | From first H1 or filename |
| -l, --language <code> | Language code (e.g., en, es, fr) | en |
| -p, --publisher <name> | Publisher name | - |
| -c, --cover <path> | Path to cover image | - |
| --description <text> | Book description | - |
| --rights <text> | Copyright/rights statement | All rights reserved |
| --identifier <id> | Unique identifier | Auto-generated UUID |
Supported Markdown Features
- Headings (H1-H6)
- Paragraphs with proper text flow
- Emphasis: italic, bold, bold-italic
- Lists: Ordered and unordered
- Links: Internal and external
- Internal Links (Wikilinks): Cross-references between chapters
- Images: Local files (automatically embedded)
- Code: Inline
codeand fenced code blocks - Blockquotes
- Tables
- Horizontal rules
- Footnotes:
[^1]with definitions
Footnotes Example
This is a paragraph with a footnote[^1].
Another paragraph with another footnote[^note].
[^1]: This is the first footnote.
[^note]: This is a named footnote.Images
Images are automatically embedded in the EPUB:

Local image paths are resolved relative to the markdown file.
Internal Links (Wikilinks)
When converting multiple markdown files into a single EPUB with chapters, you can use wikilink syntax to create cross-references between chapters:
See [[chapter2]] for more details.
See [[Chapter 2: The Investigation|the investigation]] for more details.
See [[chapters/chapter2|the analysis]].How it works:
[[target]]- Creates a link using the target as both the link and display text[[target|display text]]- Creates a link to target with custom display text
Link resolution (Obsidian-style):
The tool supports multiple matching strategies to find the target chapter:
- Filename match:
[[chapter2]]matcheschapter2.md - Path match:
[[chapters/chapter2]]matcheschapters/chapter2.md - Title match:
[[Chapter 2: The Investigation]]matches the chapter with that title - Basename from path:
[[chapter2]]matches any file ending withchapter2.mdregardless of directory
If the target matches an included chapter using any of these strategies, it creates a clickable link. Otherwise, it converts to plain text (just the display text).
Examples:
<!-- Links to an included chapter - multiple ways -->
As discussed in [[chapter1]], we found something unusual.
Reference [[chapters/chapter2|the data analysis]] from the investigation.
Continue reading in [[Chapter 3: The Revelation|the final chapter]].
<!-- Links to non-included files become plain text -->
The [[old research facility]] was closed years ago.
Consult [[Dr. Williams]] for more information.In the EPUB output:
[[chapter1]]→ clickable link to Chapter 1 (filename match)[[chapters/chapter2|the data analysis]]→ clickable link showing "the data analysis" (path match)[[Chapter 3: The Revelation|the final chapter]]→ clickable link showing "the final chapter" (title match)[[old research facility]]→ plain text "old research facility"[[Dr. Williams]]→ plain text "Dr. Williams"
This feature is particularly useful for:
- Creating a connected narrative across multiple chapters
- Cross-referencing related content
- Maintaining wiki-style documentation in EPUB format
Output Structure
The generated EPUB follows the EPUB 3.0 standard and includes:
- Proper EPUB structure:
mimetype,META-INF/container.xml,content.opf,toc.ncx - Embedded images: All referenced images are included
- Styled content: Professional CSS styling for optimal reading experience
- Metadata: Title, author, language, publisher, etc.
- Navigation: Table of contents based on document structure
Examples
Example 1: Simple Conversion
md-to-epub article.mdExample 2: Book with Metadata
md-to-epub book.md \
--title "The Complete Guide" \
--author "John Smith" \
--publisher "Tech Books Publishing" \
--cover ./cover.png \
--description "A comprehensive guide to everything"Example 3: Bulk Conversion with Config
Create .md-to-epubrc:
{
"author": "John Smith",
"publisher": "Tech Books Publishing",
"language": "en",
"outputDir": "./ebooks"
}Then run:
md-to-epub ./chapters --recursiveDevelopment
Build from Source
git clone https://github.com/yourusername/md-to-epub.git
cd md-to-epub
npm install
npm run buildRun Locally
npm start -- input.md -o output.epubProject Structure
md-to-epub/
├── src/
│ ├── cli.ts # CLI entry point
│ ├── config.ts # Configuration management
│ ├── converter.ts # Main conversion logic
│ ├── epub-generator.ts # EPUB file generation
│ ├── markdown-parser.ts # Markdown parsing & rendering
│ ├── types.ts # TypeScript type definitions
│ └── index.ts # Public API exports
├── package.json
├── tsconfig.json
└── README.mdLicense
MIT License - Copyright © 2025 Aster Haven
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Troubleshooting
Images Not Appearing
- Ensure image paths are correct relative to the markdown file
- Check that image files exist and are readable
- Supported formats: JPEG, PNG, GIF, SVG
EPUB Validation
The generated EPUBs follow the EPUB 3.0 standard. You can validate them using:
- EPUBCheck
- Online validators like EPUB Validator
Common Issues
Issue: "Cannot find module" errors
- Solution: Run
npm installto install dependencies
Issue: Permission denied when running globally
- Solution: Use
sudo npm install -g md-to-epubor configure npm to use a local prefix
Issue: Output directory doesn't exist
- Solution: The tool creates output directories automatically, but ensure parent directories are writable
Acknowledgments
Built with:
