Convert Markdown to clean PDFs with one command.
Lightweight and fully local.
You need Node.js 20 or later and one installed browser: Google Chrome, Chromium, Microsoft Edge, Brave, Vivaldi, or Firefox.
npx @cognitivesand/md2pdf notes.md
# creates notes.pdf beside notes.mdOr install the command globally:
npm install --global @cognitivesand/md2pdf
md2pdf notes.mdWorks with Bun: bunx @cognitivesand/md2pdf notes.md resolves the same npm
package.
AI assistants and coding agents write Markdown by default. Chat exports, generated reports, design documents, meeting summaries, project documentation: the volume of Markdown produced every day has grown with every model release, and most of it eventually needs to reach someone who does not read Markdown. PDF is how that document lands in an inbox, a review, or an archive.
The existing routes to a PDF each ask for a trade-off. A TeX/LaTeX toolchain means a multi-gigabyte install to convert a two-page note. Converters built on a bundled headless browser download hundreds of megabytes of Chromium per project. Online converters are the worst trade: your document leaves your machine for a server you do not control.
md2pdf takes none of those trades. It renders your Markdown in the browser you already have, entirely on your machine.
- Fully local. Your documents never leave your machine. No telemetry, no remote rendering, no network calls with your content.
- Open source. MIT-licensed, developed in the open at CognitiveSand/md2pdf.
- Complete Markdown support. Tables, task lists, footnotes, syntax-highlighted code fences, local raster images (PNG, JPEG, WebP), and Mermaid diagrams rendered to vector graphics in the PDF.
- Lightweight. Five small, actively maintained runtime dependencies. The Mermaid renderer ships inside the package as a single pinned, checksummed asset instead of pulling in its ~100-package dependency tree, and md2pdf drives the browser already installed on your system instead of shipping one.
- Minimal attack surface. Remote scripts, stylesheets, and images are never
loaded. Non-HTTPS and active link schemes (
javascript:,data:,file:, ...) are neutralized to plain text. Inputs are bounded by safety limits, and every dependency and vendored asset passes a 7-day quarantine before adoption (see the Artifact Freshness Policy).
md2pdf [OPTIONS] ENTRY [ENTRY ...]
ENTRY a Markdown file or a directory of Markdown files
-o, --output PATH output path for a single-file conversion
--output-dir DIR write every output PDF into DIR
-f, --force-overwrite overwrite existing output PDFs without prompting
-h, --help list options with one-line descriptions
--version print the version, license, and publisherExamples:
md2pdf notes.md
md2pdf notes.md --output out/report.pdf
md2pdf a.md b.md --output-dir build
md2pdf ./notes-folder
md2pdf notes.md --force-overwriteDirectory conversion is non-recursive: only top-level .md files in
the named directory are converted. The .md extension is matched
case-insensitively.
- By default,
notes.mdwritesnotes.pdfbeside the source. --outputis valid only when exactly one Markdown file is produced. The extension is used verbatim; the CLI does not force.pdf.--output-diruses each source file's base name.--outputand--output-dirare mutually exclusive.- Existing outputs are preserved unless
--force-overwriteis supplied or an interactive overwrite prompt is accepted. - In non-interactive mode, an existing output without
--force-overwriteis skipped and counted in the final summary. - Batch conversion continues after per-file conversion failures and prints a
final summary:
<succeeded> succeeded, <failed> failed, <skipped> skipped.
Exit codes:
0: every conversion succeeded, or all existing outputs were skipped without conversion failures.1: at least one conversion failed.2: invalid command-line usage.
md2pdf supports headings, paragraphs, lists, tables, task lists, footnotes, fenced code blocks, relative raster images (PNG, JPEG, and WebP), and Mermaid code fences. Browser-backed tests cover the rendered PDF behavior for the rich Markdown and Mermaid paths.
Images must be local relative files under the Markdown source directory. SVG, GIF, remote image URLs, absolute image paths, file URLs, unknown extensions, mismatched image content, and symlinks that escape the source directory are rejected before rendering.
Safe HTTPS links remain clickable in the generated PDF. Non-HTTPS, local, and
active schemes such as http:, javascript:, data:, file:, blob:, and
ftp: are rendered as text links without an href.
Safety limits enforced during rendering: Markdown documents up to 10 MB, individual lines up to 1 MB, up to 100 images, up to 50 Mermaid blocks, Mermaid blocks up to 256 KB, highlighted code fences up to 1 MB, individual images up to 20 MB, total embedded image bytes up to 100 MB, and image dimensions up to 25 megapixels.
md2pdf detects an installed browser on first run and resolves a matching
WebDriver from the artifacts declared in artifacts.json, provisioned into a
per-user cache. It does not select arbitrary drivers from PATH. For a browser
whose WebDriver ships bundled with it (such as the Firefox snap), md2pdf uses
that bundled driver after a compatibility check.
MD2PDF_BROWSER may point the converter at a specific browser executable. It
is an environment variable, not a CLI option:
MD2PDF_BROWSER=/usr/bin/chromium md2pdf notes.mdOn Windows, npm can generate both md2pdf.cmd and md2pdf.ps1 shims.
PowerShell may resolve md2pdf to the .ps1 shim first, and the local
ExecutionPolicy can block that script even when the .cmd shim is available.
Use the command shim directly when that happens:
md2pdf.cmd --helpsrc/ TypeScript sources: CLI, converter pipeline, Markdown renderer,
browser locator, WebDriver client, artifact policy
tests/ unit, integration, and browser-backed test suites plus fixtures
docs/ architecture, requirements, user stories, CI matrix, research
scripts/ artifact freshness, package, and build check scripts
assets/ default and highlight stylesheets bundled into the PDF
security/ security audit records
artifacts.json declared runtime artifacts (browsers, drivers)
ARTIFACT_FRESHNESS_POLICY.md the dependency quarantine policy
Issues and pull requests are welcome at CognitiveSand/md2pdf.
To install from source:
git clone https://github.com/CognitiveSand/md2pdf.git
cd md2pdf
npm install --global .
md2pdf --helpThe prepare script compiles dist/ during install, so md2pdf lands on your
PATH in one step on Linux, macOS, or Windows. Re-run the same command after
pulling changes.
npm ci
npm run typecheck
npm test
npm run test:contracts
npm run check:artifacts
npm run buildnpm test runs fast unit and contract coverage. npm run test:browser runs
the browser-backed integration tests and requires a local browser plus an
eligible WebDriver declared in artifacts.json. npm run test:all is the full
release gate; it runs automatically before every publish.
Publishing is automated: creating a GitHub release triggers
publish.yml, which runs the full release
gate and publishes to npm via trusted publishing (OIDC) with provenance.
Local development may set MD2PDF_SKIP_REAL_BROWSER_TESTS=1 to skip the real
browser proof explicitly; release evidence must run without that skip.
To smoke-test the exact tarball that would be published:
npm ci
npm pack
npm install --global --prefix /tmp/md2pdf-user ./cognitivesand-md2pdf-<version>.tgz
/tmp/md2pdf-user/bin/md2pdf --helpEvery artifact in md2pdf must be the newest eligible version available after a
7-day quarantine period. The policy applies to npm dependencies, transitive
lockfile entries, bundled assets, drivers, browser fallback builds, generated
vendor files, and runtime provisioning paths. There is no emergency bypass or
force mode. See ARTIFACT_FRESHNESS_POLICY.md.
The current release is published as
@cognitivesand/md2pdf
on npm; see the
GitHub releases for
version history. The release covers the user-visible CLI surface,
browser-backed Markdown rendering,
Mermaid diagrams, local WebDriver printing, overwrite/skip behavior, batch
summaries, npm packaging, artifact freshness checks, and release validation
paths.
md2pdf is built by CognitiveSand.
Discover our work at
visit cognitivesand.ai →
