Skip to main content
Back to Projects
Open Source
npm Package
TypeScript

@amitdevx/md2pdf

md2pdf is a production-grade Markdown-to-PDF rendering engine built on the Unified ecosystem (Remark/Rehype) for robust AST processing and Playwright for headless Chromium rendering. The result is a PDF that faithfully reflects modern web standards, featuring professional typography, precise margins, and correct pagination, without any browser installation friction for end users.

Version

npm version

Downloads

npm downloads

Build Status

Build Status

License

License: MIT

Runtime

Node.js >=18.0.0

Installation

Global Installation

# Install globally

npm install -g @amitdevx/md2pdf

md2pdf init

Local Installation

# Or use locally within a project

npm install @amitdevx/md2pdf

npx md2pdf init

Practical Use Cases

README.md ➔ README.pdf

import { convert } from "@amitdevx/md2pdf";

const result = await convert({input: "./README.md", output: "./README.pdf",});

Automated Release Notes

# GitHub Actions automated generation
md2pdf CHANGELOG.md --output release.pdf

Technical Documentation

md2pdf docs/architecture.md \--output build/architecture.pdf \--toc \--paper A4

Resume Generation

md2pdf resume.md \--output resume.pdf \--margin 15mm

Rendering Pipeline

md2pdf Rendering Pipeline

Playwright-powered Markdown to PDF conversion flow

ParseTransformStringifyRenderPrint01MarkdownRaw document input02Unified (Remark)Markdown AST parsing03AST RehypeHTML AST transforms04HTML + CSSString generation05PlaywrightHeadless Chromium06PDF OutputHigh-fidelity document

Key Features

  • Extensible Plugin API (Markdown, HTML, Render, Theme, Export hooks)
  • 7 professionally crafted built-in themes with strict Obsidian parity
  • Native KaTeX Offline Math (mhchem)
  • Mermaid & Architecture Diagrams
  • Obsidian callouts, wiki-links, tags, embeds, highlights
  • Batch processing with single Chromium instance
  • Config file support (md2pdf.config.ts/json/yaml)
  • md2pdf doctor & init diagnostic tooling
  • GFM tables, strikethrough, task lists, footnotes
  • Table of Contents with depth control
  • Custom headers/footers with dynamic page numbers
  • --json-errors & Structured error codes for CI
  • JavaScript & TypeScript API
  • Professional Typography & Syntax highlighting (Shiki)

Architecture Deep Dive

A detailed look into the underlying subsystems that power md2pdf's high-performance conversion pipeline.

Persistent Chromium Daemon

To optimize batch conversions, md2pdf utilizes a persistent Chromium daemon via Playwright. Instead of launching a new browser instance for every file, a single headless browser context is reused. This drastically reduces the overhead of parsing CSS and initializing V8, accelerating bulk document generation.

Incremental Content Caching

The incremental cache subsystem stores metadata in ~/.md2pdf-cache/index.json. By generating a SHA-256 hash of the Markdown AST and rendering options, the engine bypasses redundant PDF generations entirely if the source content remains unchanged, functioning similarly to a modern build system.

Extensible Plugin System

The architecture exposes a robust Plugin Registry allowing developers to hook directly into various lifecycle events: AST manipulation (Unified/Remark), HTML rendering (Rehype), and Playwright PDF generation limits. This enables custom tags, complex macros, and advanced layout overrides.

Heuristic Error Diagnostics

A heuristic diagnostic layer intercepts low-level Playwright and system errors (e.g., missing Linux shared libraries or sandbox restrictions) and translates them into actionable, human-readable instructions. This powers the md2pdf doctor command.

CLI Usage

Quick and powerful commands to generate PDFs directly from your terminal.

Single File

# Generate a PDF from a single file:

md2pdf README.md

Custom Output & TOC

# Generate a Table of Contents:

md2pdf input.md --output custom.pdf --toc

Paper Size & Margins

# Custom paper size/margins:

md2pdf input.md --paper Letter --margin 15mm

Page Breaks

# Break before H1 heading:

md2pdf input.md --h1-new-page

Batch Mode

# Convert multiple files:

md2pdf "docs/*.md" --output out_dir/

Config File

# Use JSON config:

md2pdf input.md --config md2pdf.config.json

Obsidian Vault

# Resolve local links:

md2pdf note.md --vault-root ./vault --resolve-links

CI / Errors

# Machine-readable output:

md2pdf input.md --json-errors

Debug & Verbose

# Verbose output:

md2pdf input.md --verbose

Rendered Output

Side-by-side comparison showcasing typography, syntax highlighting, and layout accuracy.

document.md
# System Architecture

The **md2pdf** engine supports native mathematics & diagrams.

```mermaid
graph TD
    AST --> Playwright
```

## Equation

$$
E = mc^2
$$
document.pdf

System Architecture

The md2pdf engine supports native mathematics & diagrams.

AST
Playwright

Equation

E = mc²

Diagnostics & Setup

Built-in tools to ensure your rendering environment is perfectly configured.

Initialization

# Initialize environment:

md2pdf init

System Health

# Check pipeline status:

md2pdf doctor

Debug Mode

# Print stack traces:

md2pdf input.md --debug

Note: Typography uses Inter and JetBrains Mono served from Google Fonts CDN. Internet access is required during conversion for correct typography. Offline environments will fall back to system fonts.

Library Usage

Embed the rendering engine directly in your Node.js applications.

import { convert } from '@amitdevx/md2pdf';


const result = await convert({

input: 'README.md',

output: 'README.pdf',

paper: 'A4',

margin: '20mm',

toc: true

});


console.log(`Render time: ${result.renderTimeMs}ms`);

OptionTypeDescription
mathbooleanEnable KaTeX/mhchem rendering
themestringCustom CSS theme path
mermaid.themestringdefault, dark, forest, neutral
pageBreaksbooleanForce page breaks on headers
metadataobjectPDF Author, Title, Keywords
header / footerstringCustom HTML templates

Release Timeline

v0.9.3 (Current)

Added --page-numbers flag to inject minimalist page numbers into the footer

v0.9.2

Cross platform Playwright Chromium discovery tests using Vitest environment mocking and fs spy mocks.

v0.9.1

--stdin flag: read markdown from stdin (pipe support).

v0.9.0

This release focuses on enterprise-level stability, cross-platform reliability, and CLI quality of life improvements....

v0.8.10

Playwright Auto-Download Fallback: Added seamless background auto-downloading for Chromium if no system browser or Pl...

v0.8.9

This release resolves several regressions from the v0.8.8 security update, fixing the batch progress counter and ensu...

v0.8.8

A security-focused release that closes a confirmed frontmatter RCE vulnerability, hardens the supply chain, and fixes...

v0.8.7

This release addresses critical UX and stability issues discovered during batch processing and system checks.

v0.8.6

Fixed Promise Hanging on Full Cache Hits: Resolved an issue where background browser initialization promises would ca...

v0.8.5

Universal Chromium Discovery: The zero-config auto-discovery system has been massively expanded. It now natively scan...

v0.8.4

JSON Output Formatting: Refined --json-errors pipeline. All nested error objects now correctly format as { error: { m...

v0.8.3

Playwright / Browser Initialization Fixes: Resolved TypeError: Cannot read properties of undefined (reading 'newConte...

v0.8.2

Cache Optimization: Playwright browser initialization is now completely bypassed when all files in a batch are alread...

v0.8.1

Incremental Rendering: Introduced a content-based SHA-256 hash caching mechanism (.md2pdf-cache/) to skip redundant c...

v0.8.0

Corrected a TypeScript compilation issue and dynamic "require" syntax resolution error in the esbuild bundle.

© 2026 Amit Divekar. All rights reserved.