Pandoc Markdown to PDF: Commands, PDF Engines, and Formatting Options

Aug 14, 2026
ByPDFtoMD

Pandoc is a Haskell library that converts between document formats. Pandoc is also a command-line tool. But what makes Pandoc special are the ways in which you can manipulate your documents.

A very important architectural point of Pandoc is that it never writes PDFs directly. That’s because writing a PDF involves quite a lot of work. So instead, Pandoc delegates this work to an external engine — either a Haskell library or another command-line tool. The external engine then takes over the task of producing the PDF.

This is a huge deal, as it allows us to leverage existing engines (such as LaTeX) when building our own Markdown documentation for PDF.

The simplest working command

Pandoc itself will convert markup into many different formats. What Pandoc does not do is write PDFs. If you want a PDF, you have to use one of the external engines.

There are several command-line flags to choose from, though most of them are used with the -t parameter to select the output format. This article discusses how Pandoc works with the PDF formats.

You need very little configuration to get a functional result:

$ pandoc pandoc-nicer-pdf.md -o pandoc.pdf

If you run this on any Markdown file, it will convert it to a basic PDF.

Selecting a PDF engine

In addition to selecting the target format, there are multiple engines available for creating PDFs. By default, if you’re using the --pdf-engine option, it will try to run pdflatex. Otherwise, it will use whichever engine you specify. There are four alternatives named by the command-line flag:

pdflatex

xelatex

lualatex

tectonic

latexmk

There is also a typst-based engine, which we’ll talk about shortly. For now, all that matters is that you pass the name of the engine to Pandoc.

Using a real workflow

We’re going to use the Typst-based engine for this particular workflow, which we’ve written up separately. Essentially, the shell script mdtopdf wraps /usr/bin/pandoc to create the PDF.

In this example, I’m passing a specific Typst template that controls the appearance of the generated PDF. In particular, the template uses A4 paper, changed margins and font, and places a logo on the first page. We installed Typst 0.12.0 from the Typst GitHub releases page and placed its binary in /usr/local/bin, where the system expects it. And, believe it or not, we created it all within one evening.

I won’t go into the specifics of how the shell script and Typst interact; rather, here’s the actual invocation that we made, showing both the input and output files:

$ /usr/bin/pandoc pandoc-nicer-pdf.md \

--pdf-engine=typst \

--template=/path/to/decoded.legal.template \

-o "$PDFFILE"

But what the shell script invokes is really just the standard Pandoc invocation. Here’s the relevant part of the shell script:

/usr/bin/pandoc $* \

--pdf-engine=typst \

--template=/path/to/decoded.legal.template \

-o "$PDFFILE"

In effect, the shell script merely passes along whatever options you specified to the standard Pandoc executable.

So the main point is that, when you invoke Pandoc to create a PDF, you’re actually invoking an engine to create it, and that engine may well have its own templates, settings, fonts, etc.

Applying the Eisvogel community template

Now, suppose that you like the Eisvogel community template. How can you apply it without having to modify your source Markdown? Well, just apply it using the following syntax:

$ pandoc file.md --template eisvogel -o pandoc.pdf

And that’s it! You can further tweak the appearance by passing variables on the command line, rather than in a YAML block at the top of the Markdown file. Why? Because you don’t want to modify the source document itself.

In this case, we’ll pass two variables: the linkcolor and whether to frame images:

$ pandoc file.md \

--template eisvogel \

-V linkcolor=blue \

-V header-includes:'\usepackage[export]{adjustbox} \usepackage{float} \usepackage{graphicx}' \

-V image:frame \

-o pandoc.pdf

What happens is that Pandoc will insert those lines inside of the header of the resulting PDF. The “frame” variable is passed to the Eisvogel template, which frames the images. If you don’t frame the images, they’ll be unframed. However, you must pass these values using the “-V” switch, not via the YAML header.

You can find the full description of what each of these parameters do at the Eisvogel site. But basically, this gives you more control over how your final PDF looks.

The extended Markdown features

Pandoc supports many additional features in your Markdown source files being converted to PDF. These include tables, definition lists, metadata blocks, footnotes, citations, and math.