How to write a programming book in Markdown

Write the prose and the listings in the same Markdown file, in fenced code blocks, and typeset them as two different things: body text at a readable measure, code in a real monospace face that is embedded in the PDF, at a size that does not wrap a 72-character line into noise. The structure is chapters as `##`, listings kept short enough to fit on one page, and a command the reader can run without guessing at the elided bits.

A programming book fails in ways a novel cannot: a listing that wraps, a command that was copied with a smart quote, a font that turned l and 1 into the same glyph on someone else's machine. Markdown is a good format for this kind of book, because the listing is still just text — but only if the rendering step treats it as code rather than as a paragraph in a fancy face.

Fenced blocks, not indented ones

CommonMark has two ways to mark a listing. Use the fence:

```python
def greet(name: str) -> str:
    return f"hello, {name}"
```

The language tag is optional for the PDF and useful for you. Indented code blocks — four spaces, no fence — look the same in a preview and then collide with nested lists, with block quotes, and with anyone who pastes from an email client that ate the leading spaces. Fences survive that.

Do not put a listing in a screenshot unless the point of the figure is the IDE around it. Screenshots of code are how a book becomes unsearchable, uncopyable, and blurry on a retina display the author did not own.

The line-length problem

Prose wants 60 to 75 characters on a line. Code often wants 80 or 100, and wrapping a listing is not the same as wrapping a paragraph — the break is now in the wrong place in the program. The measure is still the constraint; the listing has to live inside it, not the other way around.

  • Keep listings short. A 40-line function on one page is readable; the same function across a page break, with the signature on the previous sheet, is how readers lose the thread.
  • Wrap the source, not the output. If a line is 120 characters, break it in the manuscript the way you would in a codebase with a linter, not with a CSS pre-wrap surprise in the PDF.
  • Elide the boring bits with a comment (# ... setup from chapter 3) rather than pasting three pages of imports so the listing is "complete". Completeness that nobody reads is not a virtue.

The typeface has to be in the file

If the PDF says "Courier" and Courier is not embedded, the machine that opens it will substitute something else. On a developer’s laptop that something else might be fine. On a Kindle app, a corporate Windows image, or a printer, it might map 0/O and 1/l on top of each other. Embedding is not optional for a book whose meaning sits in the punctuation.

Pick a monospace with a real italic and a real bold if you will use those — many "coding" fonts have only one weight, and a renderer that is asked for bold will fake a stroke that looks worse than staying regular. 9 or 10 point, on a slightly looser line-height than the body, is the range that stays readable without shouting.

Structure that technical readers actually use

ElementMarkdownWhy
Chapter## plus a page breakOne topic, start on a fresh page
Section###The unit people skip to
ListingFenced block, kept on one pageThe thing they will copy
Command the reader runsIts own fence, no wrapping, no smart quotesIf this is wrong, nothing else matters
OutputA separate fence, or a block quoteSo it cannot be mistaken for input
Warning / asideA paragraph you label, not a colour you cannot see in printPrint is still how a lot of these books are read

Number the listings if the prose will refer back to them ("see Listing 4"). Do it in the heading above the fence, not in a caption system the Markdown flavour does not have. Cross-references that depend on a plugin are the first thing that breaks when you change renderer.

What Markdown will not do for you

Syntax highlighting in the PDF is renderer-specific and often uglier in print than in a dark IDE. A book can live without it; it cannot live with a highlight theme that turns comments the same colour as the paper. If you highlight, proof a printed page, not a preview on a screen.

Line numbers in listings, callouts (① ② ③) into a block, and "start at line 40 of a 400-line file" are all layout features. Pandoc plus a listing package can do them; a lightweight Markdown-to-PDF tool generally cannot. Write so you need them less: shorter blocks, more words around them, a repository the reader can clone.

Mathematics is the other fork. If the book is really a maths book with some Python, Pandoc and LaTeX is still the correct stack. If it is a programming book with the occasional expression, Unicode and a fenced block will do.

In bukpress

bukpress renders fenced blocks in a 10pt monospace face, padded, with break-inside: avoid so a listing tries to stay on one page rather than splitting through the signature. Long lines wrap (pre-wrap) — which is the safety net described above, not a reason to stop shortening them. There is no syntax highlighting and no line-number gutter; a listing is type on the page.

Body, title and subtitle are chosen separately, so the prose can be a serif at 11pt while the listings stay monospace. Whatever you pick is embedded in the PDF and packaged into the EPUB, which is the difference between a book that still reads on a machine that has never seen your font, and one that does not.

Read next

Design · 5 min read

Book typography for people who are not typographers

Most of the gap between an amateur page and a professional one comes down to six things: line length, type size, line spacing, margins, how many typefaces you use, and whether the heading sizes form a clear hierarchy. None of them require taste to get right — they have known good ranges.

Read it
Explainers · 4 min read

Why your PDF looks wrong on someone else's computer

Because the font was referenced rather than embedded. A PDF can either carry a copy of the typeface inside the file or just name it and hope the reader's machine has it — and when it does not, the reader silently substitutes something else, which changes the line breaks and the page count along with the look.

Read it
How-to · 5 min read

How to control page breaks in Markdown

Markdown has no page break because it describes structure, not pages — so every method is really an instruction to whatever renders it. The three that work are a raw HTML div with a CSS page-break rule, a LaTeX \newpage command through Pandoc, or a renderer that assigns a meaning to a plain-text marker.

Read it

Write it in Markdown. Ship a book.

bukpress turns the file you are already writing into a typeset PDF and EPUB — your type, your covers, no watermark on any plan.

Start free — no card required