Converting a Markdown README to a PDF
You have a README.md and somebody wants it as a PDF. A grant application that only accepts
attachments, a client who does not have a GitHub account, a printed appendix for a dissertation, or
an archive of a repository that may not exist in five years.
GitHub has no export button. Your editor's preview prints with a sidebar down the side of it. And the first converter you tried handed back a file with a row of empty boxes where the build badges used to be.
That last part is not a fault in the converter. Markdown to PDF is a lossy trip, and it is worth knowing what falls off the back before you attach the file to anything.
Why the badges are always the first thing to go
There are two families of Markdown-to-PDF converter, and they lose different things.
The first family renders your Markdown to HTML, opens it in a headless browser, and prints the page. It gets everything a browser can do: stylesheets, web fonts, coloured syntax highlighting, and — the part that matters here — an HTTP request for every image on the page. Badges survive because a browser genuinely goes to shields.io and fetches them.
The second family, ours included, is a text layout engine. It reads the structure out of the markup
— this is a level-two heading, this is a bullet, this is a fenced code block — and sets that
structure in real type on real paper. There is no browser, no network fetch and no image
compositor anywhere in it. So  has nothing to draw with. The
address is dropped and the alt text is kept as words.
That is the whole trade, and it decides which route you should take. A browser-based converter looks like the GitHub page and needs a browser installed. A text converter gives you a clean typeset document and quietly discards anything that needed rendering.
What survives the trip
Run a README through Word to PDF and this much comes across intact:
- Headings.
#through######become real headings, sized relative to the body text you choose, so raising the text size scales the whole document rather than only the paragraphs. - Lists. Bullets and numbered items, including nesting — two spaces of indent per level.
- Blockquotes. Set in italic with a rule down the left margin.
- Fenced code blocks. Verbatim and monospaced. Line breaks are kept, leading indentation is kept, and tabs are expanded to four spaces. A line too long for the measure wraps rather than running off the edge.
- Links. The words plus the address in brackets:
[the docs](https://example.com)arrives as "the docs (https://example.com)". Nothing is clickable, which is the right answer on paper. - Horizontal rules, drawn as a real rule.
Two things about code blocks specifically. Only fenced blocks count — the older style of marking code by indenting it four spaces is read as ordinary paragraph text and reflowed, which mangles it. And there is no syntax highlighting: you get plain monospace, never colour.
What does not survive
- Every image. Badges, screenshots, logos, architecture diagrams. Nothing is fetched or embedded, and what is left on the line is the alt text.
- Emphasis. The
**and*markers come off the words, but the words are not set bold or italic in body text. Headings are bold; a bold phrase inside a paragraph is not. - Task-list checkboxes.
- [x] Ship itcomes out as a bullet followed by the literal characters[x]. Readable, but not tick boxes. - Mermaid diagrams. A fenced block tagged
mermaidis a code block like any other, so you get the diagram's source verbatim. Nothing draws it.
None of that is GitHub-flavoured Markdown being read badly. It is standard Markdown being read correctly, and GitHub's flavour being something else. Compare the output against your source rather than assuming a line-for-line match.
Converting it
- Check the file extension. Word to PDF decides how to read the file from
its name first:
.mdand.markdownare read as Markdown,.txtas plain text,.htmlas HTML. A README saved without an extension gets sniffed instead, which usually works and is not worth relying on. - Upload it and choose the paper. A4 or Letter, the margin in millimetres, the body text size between 7 and 18 points, and one of four typefaces. Times New Roman or PT Serif if it is going to be printed; Helvetica or Open Sans if it will be read on a screen.
- Read the note that comes back. It says which reader it used — "Read as Markdown." If it says
plain text, the extension was wrong and every
#is now a literal hash in a paragraph. Rename and run it again. - Check the seams. Text is flowed onto pages, so a heading can land at the foot of one with its section starting overleaf. There is no widow control and no keep-with-next. If it lands badly, change the margin or the text size by a point and the breaks move.
If the tables matter, go through HTML
Render the Markdown to HTML first — pandoc README.md -o README.html, or your editor's export, or
saving GitHub's rendered page from the browser — and put that through
HTML to PDF. It has the same no-CSS, no-images, no-JavaScript rule, but it does
read tr, td and th, so each row arrives as a row of cells separated by pipes in monospace.
That is not a ruled table, but it is legible and the columns still line up as data.
If somebody downstream wants those numbers in a spreadsheet rather than on a page, that is a different trip entirely, and it is easier to hand them the original Markdown than to extract the table back out of the PDF you just made.
The contents list will not jump anywhere
A README's table of contents is a list of fragment links — [Installation](#installation). Those
resolve inside a rendered HTML page and mean nothing in a PDF, so what you get is the item text
followed by a dangling (#installation).
There are no PDF bookmarks either, and no link annotations of any kind. If the document is long enough that navigation matters, delete the contents list from a copy of the Markdown before converting; it costs nothing and reads better than a column of dead anchors.
What this will not do
It does not convert .docx. The tool is called Word to PDF and it refuses actual Word files,
because rendering one faithfully means implementing Word's layout engine and the practical answer
everybody uses is LibreOffice, which is not installed here. It says so instead of returning
something nearly right. If you have a Word document, use Save As PDF in Word itself.
It adds nothing to the page. No headers, no footers, no page numbers, no table of contents. For a printed appendix, run the finished file through Add page numbers to PDF — it stamps the figure into the page content, so it prints and survives being merged into something larger. If you want to know how many pages you ended up with, or confirm the page size before sending it to a printer, our PDF inspector reads that out of the file.
Several documents, one PDF
Repository documentation is rarely one file. Convert README.md, CHANGELOG.md, CONTRIBUTING.md
and LICENSE separately, then put the PDFs into Merge PDF in the order you want
them read. Leave the per-file bookmark option on and each document leaves a named entry in the
outline at the page where it starts, which gives the combined file the navigation the individual
conversions could not. Rename the files to something readable first — the bookmark is named after
the file.
When a real toolchain is the better answer
If you are doing this more than once, or the badges and screenshots are the point, stop using a web converter:
- Pandoc is the standard answer:
pandoc README.md -o README.pdfwith a LaTeX engine installed, orpandoc README.md -o README.pdf --pdf-engine=weasyprintif you would rather not install LaTeX. It understands GitHub-flavoured Markdown properly, including tables, and will fetch local images. - md-to-pdf drives a headless Chromium, so you get images, real tables and syntax highlighting — the browser family described at the top.
- VS Code's Markdown PDF extension is the no-terminal version of the same thing, and it is one right-click on the file you already have open.
- Open the repository page on GitHub and use your browser's Print to PDF. Crude, and it drags in the site navigation, but the badges and the screenshots are there because a browser fetched them.
Ours is the right tool when you want a typeset document rather than a screenshot of a web page and would rather not install a LaTeX distribution to get one. Either way, read the result before it goes anywhere that matters — a README is written to be scrolled, and page breaks are the one thing its author never had to think about.