Qmd Documents

Introduction to qmd – markdown on steroids

Qmd documents are Markdown documents, but with loads of extra functionality provided by Quarto and Pandoc. nbdev uses Quarto to render its pages (with some extra functionality), and Quarto uses Pandoc to render its pages (with some extra functionality). Every markdown cell in an nbdev notebook is treated as qmd, and nbdev can publish plain qmd text files, and qmd RenderScripts. Therefore, it’s a good idea to be familiar with the main features of qmd.

Just like with RenderScripts, you can use hot/live reloading with plain qmd text files – so as soon as you save the file, you’ll see the new output in your web browser (assuming you’ve got nbdev_preview running).


You can generate data-driven documents using qmd files. For instance, consider this table (also shown in the RenderScript tutorial for comparison), containing a list of the people with testimonials on nbdev’s home page:

Name Position
Chris Lattner Inventor of Swift and LLVM
Fernando Pérez Creator of Jupyter
David Berg Software Engineer, Netflix
Erik Gaasedelen Software Engineer, Lyft
Roxanna Pourzand Product Manager, Transform
Hugo Bowne-Anderson Head of Developer Relations, Outerbounds

The table above is generated using an embedded qmd computation block from the following python list:

testimonials = [
    ('chris-lattner.png', 'Chris Lattner', 'Inventor of Swift and LLVM'),
    ('fernando-pérez.jpeg', 'Fernando Pérez', 'Creator of Jupyter'),
    ('david-berg.jpeg', 'David Berg', 'Software Engineer, Netflix'),
    ('erik-gaasedelen.jpeg', 'Erik Gaasedelen', 'Software Engineer, Lyft'),
    ('roxanna-pourzand.jpeg', 'Roxanna Pourzand', 'Product Manager, Transform'),
    ('hugo-bowne-anderson.jpeg', 'Hugo Bowne-Anderson', 'Head of Developer Relations, Outerbounds')

Just like in the RenderScript example, to produce the table from this python list, the following four lines of code are used:

for fname,name,position in testimonials:
    print(qmd.tbl_row([im(fname, 60), name, position]))

For data-driven documents such as this one, we add the following to the YAML frontmatter, which hides the code used to produce outputs, and also does not add any extra formatting to outputs:

  echo: false
  output: asis

Compare the source code of the RenderScript example and of the current page to see how computations are used in RenderScripts compared to plain qmd text files. We find that we like to use Notebooks for most pages we build, since they’ve got so much helpful functionality (such as pasting images directly into cells). We use RenderScripts for complex web pages like the nbdev home page, and qmd files for pages that are mainly markdown and don’t need any notebook functionality.


In addition to the standard markdown formatting, Quarto qmd adds many additional features. Look at the full quarto docs to see everything it can do – we’ll just highlight a few of our favorites here.

Divs and classes

You can create HTML divs, by surrounding lines with :::. Divs can include classes by placing {.classname} after the opening :::. Here’s an example:

::: {.border}
This content can be styled with a border

This is how that’s rendered:

This content can be styled with a border

You might be wondering where that border class comes from… Quarto comes with support for Bootstrap 5 and Bootswatch themes so there’s lots of classes available you can use in your documents. Remember, all notebook markdown cells are also considered qmd, and can also use all the formatting tricks discussed in this section.


A special kind of block you can use is the callout block. Here’s an example:

Note that there are five types of callouts, including:
`note`, `warning`, `important`, `tip`, and `caution`.

…and here’s how it’s rendered:


Note that there are five types of callouts, including: note, warning, important, tip, and caution.


You can add images (quarto calls them figures to your document, along with captions, and you can even arrange them into layouts. Here’s an example:

::: {layout-ncol=3}