How I built bukpress, a Markdown to ebook tool
Paste Markdown, get a typeset book. Getting there took a hand-mirrored stylesheet, an EPUB rewritten from scratch, and a security hole closed in the first week.
bukpress turns a Markdown draft into a typeset PDF and EPUB, with a live paginated preview. I started it on 29 July 2026 as a web port of a small desktop PDF tool from another of my projects. The first version took four days, and those days included an EPUB rewritten from scratch and a security hole that could have put server secrets inside a customer's PDF. The weeks after went into the part a reader never sees: keeping the browser preview and the server export in step. It is the oldest of my tools, and every guide on this site is made with it.
Why it exists
The writing is done. Then the pages start fighting back.
Anyone who has made a lead magnet or a workbook in Word or Canva knows the list: pressing Enter to push a stranded heading onto the next page, copying a table's header row onto the page it spills onto, exporting, finding the bad break, fixing it, exporting again. Then rebuilding fonts and margins for the next book.
I wanted something between a writing tool and a page layout app. No InDesign, and no Pandoc and LaTeX toolchain to configure. Formatting an ebook compares the options if you are choosing today; this post is about building one of them.
Where it came from
bukpress did not start from nothing. Another of my projects already had a desktop app for turning Markdown into PDFs. The page break rules, the four bundled font families and the layout of the type scale all came from it. The web version began life as markdown-to-pdf-saas and was renamed in August.
The rename is still visible underneath. The storage bucket and the database keep the old name, on purpose: renaming a live bucket breaks every upload and export that points at it, and nobody but me ever sees the name.
The stack, and one odd choice
- A Rails API with Postgres, a Redis job queue, S3 storage and Stripe.
- A Python worker that renders the PDF with WeasyPrint and builds the EPUB with ebooklib.
- A React web app with a live preview built on Paged.js.
The odd choice is Rails 6.1 when Rails 8 existed. The first version was built in a sandbox that could install Rails only from the operating system's package manager, with no access to the gem registry. The upgrade is deferred and written down as deferred, because upgrading a framework blind on a live product is how you lose a weekend.
Two engines, one spec
This is the heart of the product and the hardest part of it.
The export is rendered on the server by WeasyPrint. The preview is rendered in your browser by Paged.js. They are different engines, so the page rules exist twice: once in Python on the server and once in a hand-written TypeScript copy in the browser. Both implement the same CSS paged media rules. The engineering notes are honest about the limit: the preview should closely match, it is not guaranteed to be pixel identical, and the export is the source of truth.
Most of the bugs in the preview were small mismatches between the two:
- Images measured zero height before they loaded, which threw off every page after them. Images are now preloaded.
- Hiding a page the obvious way broke the page counter.
- Bold headings were faked in the preview and used the true weight in the export.
- A page break straight under a paragraph showed up as literal dashes in the preview.
- Leaked stylesheets made the editor slower the longer you wrote.
The server is authoritative wherever it matters. Page limits are checked on the real rendered PDF, never the preview's count. There is also a ceiling on input before rendering, so a free account cannot make the server lay out fifty thousand pages before being told no. The note on that fix says "the ordering was the bug", which is true of a lot of bugs.
What broke
No font a user chose had ever reached a PDF
WeasyPrint needs a font configuration passed in explicitly, or it silently drops every custom font rule. So every export came out in Liberation Sans while the preview showed the font you picked. The preview looked right, so the bug looked like nothing.
There is a regression test for it now. Fonts became one library per account early on, Google Fonts can be imported, and on the top plan you can upload your own.
The EPUB was broken four ways
On 30 July I rewrote the EPUB from scratch. The first version had lost its fonts through wrong relative paths, was missing font faces, opened with a blank page, and put the whole book in one file with a one-line table of contents. A page background made text unreadable in night mode readers, so the EPUB now carries the background colour only and drops the image.
A Markdown file could read the server's secrets
Fixed on 1 August, and the reason the worker sanitises everything now. Raw HTML in Markdown let a link tag point at a file on the worker's own disk, including the one that holds its environment, and embed it into the delivered PDF. That would have put storage keys and an internal token inside a customer's download. Scripts also reached the EPUB untouched, and the job payload could redirect the internal token to any host.
The same day I added limits for oversized images, render timeouts and memory caps, and fixed jobs that could be lost from the queue. None of this shows on the landing page. All of it is the difference between a product and a liability.
Smaller ones
- A documented setting for the allowed web origin was never read by the code, so following my own docs would have shipped production broken.
- A deploy step that ran database migrations was removed on 1 August. Two migrations in September never ran, and the app returned errors until the step came back.
- The landing page's prerender was silently unhooked for almost three weeks, so search engines got an empty page. It came back with 107 build checks so it cannot happen quietly again.
What a usability review changed
I paid for a usability review. Two findings changed the product.
The reviewer could not tell who bukpress was for or what came out of it. The hero now names the reader (creators, coaches and indie authors) and the files: lead magnets, workbooks, course handouts, ebooks and whitepapers.
The reviewer also never discovered that three dashes on a line start a new page, which is the single most useful thing in the editor. So there is now a Markdown guide in a drawer, a Page break button, and the editor and preview follow each other: click a paragraph and the preview jumps to it.
An earlier fact-check pass had already corrected fourteen claims on the site, including the page size. The login page once said A4 and Letter. Letter has never been supported, and the line came out.
How it works now
You paste Markdown. A line of three dashes is a page break, every top-level heading starts a new page, and tables repeat their header row on each page they cross. You pick fonts, colours, paper and covers, save them as a Brand Kit, and the next book uses the same design in one click. You download an A4 PDF, and an EPUB on the higher plan. There is no watermark on any plan, the free one included.
Colour emoji are a small example of the work underneath: WeasyPrint cannot lay out colour emoji fonts, so each emoji is swapped for a PNG from Noto Color Emoji.
Who it is for, and who it is not for
For: creators, coaches and indie authors making text-led PDFs: lead magnets, workbooks, course handouts and guides. If you are still writing, how to write an ebook comes first.
Not for:
- A paperback with a trim size. Export is A4 only.
- Image-led layouts like planners. Use Canva.
- A fixed-layout EPUB. The EPUB is reflowable; fixed layout is deferred.
- An unfinished draft. No tool fixes that.
Easy Reels runs on the same shape as bukpress: a web app, an API and a Python worker on a queue. And if you are curious how the newest tools compare, Copix was built in two days because the boring parts already existed.
bukpress, if the layout is what slows you down
A note on fit first. If your ebook is ten pages and already looks fine in Google Docs, export it and move on. bukpress does not write the book, and it will not make an unwanted book sell.
bukpress turns a Markdown draft into a typeset PDF and EPUB: a live paginated preview, your own fonts and covers, a design you save once and reuse, and no watermark. There is a free plan, so you can run a real manuscript through it first.
Frequently asked questions
What is bukpress?
A web app that turns Markdown into a typeset A4 PDF, and a reflowable EPUB on the higher plan. You paste the text, choose a design, see the paginated pages live and download the file.
How does bukpress make the PDF?
A Python worker renders it with WeasyPrint from a CSS paged media stylesheet. The live preview in the browser uses Paged.js with a mirrored copy of the same rules.
Does the preview match the export exactly?
It follows the same page rules, and a long list of mismatches has been fixed. The export is the source of truth: page limits, for example, are checked on the real rendered PDF.
Can I make a paperback for Amazon KDP with bukpress?
Not today. The PDF export is A4 only, so a 6 by 9 inch paperback needs a different tool.
Is there a free plan?
Yes, with limits on exports and pages, and no watermark on any plan.
The system behind this, written down
Everything above is the map. The Income Loop is the work inside it: modules 0–6 from the problem you solve to the offer that pays for it, plus ten traffic paths: the deeper post banks, the content sales systems and the full software build sequence, in one place.
Get The Income LoopNot ready to pay for anything? The Basic Income Loop is free and includes a complete seven-day starter for Threads, Instagram or software, enough to find out which one suits you before spending anything.