← All posts

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 ![Build](https://img.shields.io/...) 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:

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

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

  1. Check the file extension. Word to PDF decides how to read the file from its name first: .md and .markdown are read as Markdown, .txt as plain text, .html as HTML. A README saved without an extension gets sniffed instead, which usually works and is not worth relying on.
  2. 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.
  3. 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.
  4. 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:

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.