Getting Started with Quarto — Create Dynamic Reports in R
Getting started with Quarto means adopting an open-source scientific and technical publishing system. It extends R Markdown to support multiple programming languages including Python, R, Julia, and Observable. Quarto produces high-quality documents, books, presentations, dashboards, and websites from your code.
If you already use R Markdown, Quarto will feel familiar. It offers improved performance, better output formats, and a cleaner syntax. This tutorial walks you through creating your first Quarto document.
What you’ll learn
This tutorial covers the key concepts and practical techniques for working with Getting Started with Quarto. By the end, you will know how to apply the core functions in real data analysis workflows.
Why use Quarto?
Quarto solves several pain points in R Markdown. The syntax is cleaner with the #| option system replacing the chunk label approach. Rendering is faster, especially for documents with many code chunks. Quarto produces output that looks better out of the box, with improved styling for HTML, PDF, and Microsoft Word formats.
Another major advantage is multi-language support. A single Quarto document can contain R, Python, and Julia code in the same file. This makes Quarto ideal for projects that combine different tools. The output formats are consistent regardless of which language your code uses.
Installing Quarto
Quarto is a standalone tool that works with or without RStudio. Install it from the official website:
- Download the installer for your operating system from quarto.org
- Run the installer
- Restart RStudio—Quarto should now appear in the toolbar
You also need the quarto R package:
install.packages("quarto")
After installing the package, confirm that Quarto is available and properly configured by checking the installed version. A successful return value looks like “1.4.0” or higher — anything below 1.0 indicates an older CLI that should be upgraded separately from the quarto.org website.
quarto::quarto_version()
This should return a version number like “1.4.0” or higher.
Your first Quarto document
Open RStudio and select File > New File > Quarto Document. Choose HTML as the output format and give your document a title.
A new file opens with default content. Delete everything and start with a YAML header between --- delimiters:
---
title: "My First Quarto Document"
format: html
---
Below the header, add sections with ## headings and R code chunks. The #| lines inside the code block are Quarto chunk options — they control execution behavior without using the knitr {r option=value} syntax. This language-agnostic format works identically whether you write R, Python, or Julia code in the same document.
#| echo: true
# Calculate the mean of some numbers
numbers <- c(10, 20, 30, 40, 50)
mean(numbers)
You can also mix inline R expressions in prose: The mean is r mean(numbers). (with backticks around the expression) renders the computed value inline.
Save this file as hello-quarto.qmd.
Understanding the parts
The top section between the --- lines is the YAML header. It specifies metadata like the title and output format. The format: html tells Quarto to render an HTML document.
The ## headings create sections. Code blocks live between the “ ```r ```` markers.
Notice the #| lines inside the code block. These are inline options that control how the code behaves. #| echo: true prints the code alongside its output.
Rendering your document
Click the Render button in RStudio’s toolbar. Your browser opens showing the rendered HTML document. The code, output, and narrative text all appear together.
You can also render from the R console:
quarto::quarto_render("hello-quarto.qmd")
You can also call Quarto directly from the terminal without going through R at all. The quarto CLI command provides the same rendering behavior and is useful in shell scripts, CI/CD pipelines, and Makefiles where you want to avoid launching an R session just to render a document.
quarto render hello-quarto.qmd
Code chunk options
Quarto provides dozens of chunk options that control execution and display. Here are the most useful ones:
| Option | What it does |
|---|---|
echo: false | Hide the code, show only output |
include: false | Run the code but hide everything |
output: true | Show output (default) |
warning: false | Suppress warnings |
error: false | Continue on errors |
collapse: true | Put output in same block as code |
cache: true | Cache results for faster rebuilds |
message: false | Suppress messages |
Apply these options directly in your chunk:
#| echo: false
#| warning: false
library(ggplot2)
Rather than repeating the same options on every chunk, define global defaults in a setup chunk placed at the top of your document. Chunk-level #| options override the global settings, so you can set sensible defaults (like suppressing warnings) and enable them per-chunk where the output is diagnostically useful.
#| include: false
# Set global options
opts <- knitr::opts_chunk$set(
echo = TRUE,
warning = FALSE,
message = FALSE
)
Creating different output formats
One Quarto source can produce multiple outputs. Change the format field in your YAML header:
HTML
Set format: html in the YAML header to produce a self-contained web page. HTML is the default format, requires no additional tools, and supports the full range of Quarto features including interactive widgets, tabsets, and collapsible code blocks.
Set format: pdf to produce a paginated document suitable for printing and distribution. PDF output requires a working LaTeX installation on your system. If you do not already have LaTeX, the tinytex package provides a lightweight distribution that installs in a single R command. This avoids the multi-gigabyte download of a full TeX Live installation and includes only the packages commonly needed for R-generated PDF documents.
install.packages("tinytex")
tinytex::install_tinytex()
Microsoft Word
Set format: docx to produce a .docx file useful for collaborative workflows where colleagues edit in Word and you render from code. The document preserves your text and code output while allowing reviewers to use Word’s track-changes and commenting features. Quarto can also embed formatted tables — the gt package renders data frames as publication-quality HTML tables inside the Word document, with headers, footnotes, and cell formatting preserved in the conversion.
library(gt)
mtcars[1:5, 1:4] |>
gt::gt() |>
gt::tab_header(title = "Motor Trend Cars")
Presentations
Quarto handles slide decks the same way it handles documents — declare the format in YAML and write your content in the body. Two presentation engines are supported: Beamer for PDF slides and Reveal.js for HTML-based interactive presentations. For Beamer, which generates a PDF slide deck using LaTeX:
---
title: "My Presentation"
format: beamer
---
For HTML-based presentations that run in any browser without a PDF viewer, Quarto supports Reveal.js. This format renders slides as interactive web pages with support for animations, incremental reveals, speaker notes in a separate window, and embedded interactive code. Choose Reveal.js when your audience will view the slides online and you want to include dynamic elements like live plots or embedded Shiny apps.
---
title: "My Presentation"
format: revealjs
---
Reveal.js presentations support animations, speaker notes, and embedded code that runs live during the talk. Each level-two heading (##) creates a new slide, and you can add incremental reveals, background images, and custom themes through YAML options. The HTML output works in any modern browser without plugins or special viewers.
Embedding plots
Data visualizations are a core feature of any technical document, and Quarto handles plots generated by R or Python automatically. When you create a plot in a code chunk, Quarto saves it as an image file and embeds it in the output at the correct resolution for the target format. You can control the plot dimensions, caption, and cross-reference label directly from chunk options without writing any additional Markdown:
#| label: simple-plot
#| fig-cap: "A simple scatter plot"
library(ggplot2)
ggplot(mtcars, aes(x = wt, y = mpg)) +
geom_point() +
theme_minimal()
The #| label: option assigns a name for cross-referencing. The #| fig-cap: adds a caption that appears below the plot. Quarto automatically numbers figures sequentially throughout the document and generates clickable cross-reference links in HTML output. You can also set fig-width and fig-height in chunk options to control plot dimensions in the rendered output.
Tables and data
Quarto renders data frames and tables in multiple formats depending on your output target. For HTML, data frames display as formatted HTML with sortable columns. For PDF, they render as LaTeX tables. The simplest way to embed a data table is with the kable function from the knitr package, which produces clean bordered tables out of the box:
library(knitr)
kable(head(mtcars), caption = "First rows of mtcars")
Beyond programmatically generated tables from R code, Quarto also renders plain Markdown tables written directly in the document body. These are useful for small lookup tables, configuration summaries, and data that does not change between renders. The syntax uses | characters to define column boundaries, with a separator line of dashes below the header:
| Column 1 | Column 2 |
|----------|----------|
| Data 1 | Data 2 |
Including external files
For larger projects, keeping all content in a single .qmd file becomes unwieldy. Quarto lets you pull in external content from separate files, which keeps your main document focused on structure while the included files handle boilerplate like custom headers, footers, and shared CSS. The YAML header controls which files get included during rendering:
---
title: "My Report"
format: html
include-in-header: header.html
include-after-body: footer.html
---
This keeps large documents organized by separating content into manageable pieces — headers go in one file, footer disclaimers in another, and the main document only contains the narrative content specific to that report. For code, Quarto provides a dedicated chunk option that reads and executes an external R or Python script without pasting its contents into the document:
#| file: scripts/analysis.R
This reads and executes the R script at scripts/analysis.R without copying its contents into the document. The advantage over copy-pasting is that your analysis code stays versioned separately, can be tested independently, and multiple Quarto documents can share the same analysis script without duplication.
Document structure
Every Quarto document follows the same three-part layout that separates metadata from content. The YAML header at the top specifies output format and rendering options, the body contains your prose in Markdown, and code chunks hold executable code blocks that Quarto evaluates during rendering. A typical YAML header looks like this:
---
title: "My Report"
format: html
execute:
echo: false
---
execute: echo: false hides code globally. Override per chunk with #| echo: true. eval: false skips chunk execution. warning: false and message: false suppress R warnings and messages from appearing in the output.
Code chunks
Code chunks are fenced with ``` and a language identifier. R chunks use ```{r}. Python chunks use ```{python}. Both can appear in the same document, sharing data through reticulate. Chunk labels (#| label: fig-sales) enable cross-references: @fig-sales in prose creates a numbered figure reference.
Output formats
The format key selects the output: html, pdf, docx, revealjs (slides), dashboard. Multiple formats in one document: format: [html, pdf]. PDF requires a LaTeX installation; tinytex::install_tinytex() installs a lightweight distribution. quarto render doc.qmd --to pdf renders a specific format from the command line without changing the document’s default format.
Including figures and tables
fig-cap: "My caption" in chunk options adds a figure caption. tbl-cap: "Table caption" captions tables. knitr::kable(df) renders a data frame as a formatted table. gt::gt(df) creates a publication-ready table with styling options. kableExtra::kable_styling() adds Bootstrap styling to knitr::kable() tables.
Figure cross-referencing: label a chunk with #| label: fig-sales, then reference it as @fig-sales in text. Quarto substitutes the figure number automatically. Sections, tables, and equations follow the same pattern with sec-, tbl-, and eq- prefixes.
Output formats and format options
Quarto supports dozens of output formats through a unified YAML interface. The format key in the document YAML controls which renderer runs. Common formats and their key options:
For HTML reports: format: html with toc: true (table of contents), code-fold: true (collapsible code blocks), theme: cosmo (one of many Bootswatch themes). The self-contained: true option embeds all CSS and JavaScript into the HTML file, making it portable for sharing without a web server.
For PDF reports: format: pdf uses LaTeX by default. format: typst is a faster alternative introduced in Quarto 1.4 that does not require a LaTeX installation. For academic papers, format: pdf with documentclass: article and a CSL bibliography file handles citations through Pandoc’s citeproc.
For Word documents: format: docx with reference-doc: my-template.docx lets you supply a Word file whose styles Quarto will use, allowing brand-consistent output.
Chunk options and execution control
Each code chunk can carry options as special comments (#| option: value) placed at the top of the chunk, or as attributes on the fence (```{r, echo=FALSE}). The #| syntax is preferred in Quarto because it is language-agnostic and works for Python, Julia, and Observable chunks as well.
Key chunk options:
echo: false, run the code but hide the sourceeval: false, show the code but do not run itinclude: false, run the code but hide both output and source (useful for setup chunks)warning: false/message: false, suppress R warnings and messages from appearing in outputcache: true, cache the chunk output to disk; re-run only if the chunk code changes
Global defaults go in the document YAML under execute:, for example:
execute:
echo: false
warning: false
Chunk-level options override the global defaults, so you can set echo: false globally to hide code in a report while still showing it for specific tutorial chunks where the code itself is instructive. This pattern of global defaults with local overrides is the recommended way to manage document-wide styling without repeating options on every chunk.
Cross-References
Quarto has a built-in cross-reference system that automatically numbers figures, tables, equations, and sections as you add or remove them. Label a figure chunk with a label starting with fig- and Quarto handles the numbering and linking throughout the document:
#| label: fig-scatter
#| fig-cap: "Relationship between weight and mpg"
plot(mtcars$wt, mtcars$mpg)
Then reference it in text with @fig-scatter and Quarto inserts “Figure 1” (or the appropriate number). Tables use tbl- prefixes, equations use eq-, and sections use sec-. Numbering is automatic and updates as you add or remove items.
Parameterised reports
Quarto supports parameterised rendering through params in the YAML front matter:
params:
region: "North"
year: 2025
Inside the document, access parameter values with params$region and params$year. To render with different parameters from the command line: quarto render report.qmd -P region:South -P year:2024. This pattern enables a single template to produce many region- or year-specific reports in a loop.
Quarto projects
A Quarto project is a directory with a _quarto.yml file. The project type (book, website, manuscript) controls how Quarto links and renders multiple documents. A website project renders each .qmd file to a separate HTML page, generates a shared navigation bar from the navbar key, and shares a _freeze/ directory for cached computations across files.
For a data team, a Quarto website is a practical way to host multiple analyses under one URL: each analyst writes their own .qmd file, the project builds them together, and CI/CD publishes the result. The quarto publish command supports Quarto Pub, GitHub Pages, Netlify, and Posit Connect as deploy targets.
Quarto vs R markdown
Quarto is the successor to R Markdown, designed to be language-agnostic (R, Python, Julia, Observable) and to unify the ecosystem. Key differences: Quarto uses #| comments for chunk options (language-agnostic syntax) instead of knitr’s {r option=value} header syntax. Quarto documents have a .qmd extension. The rendering engine is quarto render rather than rmarkdown::render().
Most R Markdown documents render correctly with Quarto without modification because Quarto includes a compatibility mode. Migrating gradually is practical: new documents use .qmd, existing .Rmd documents continue to work.
The biggest practical improvement is multi-language support in a single document. A Quarto document can have R chunks for statistical analysis and Python chunks for machine learning, sharing data through the reticulate bridge. Python variables are accessible from R as py$variable and R variables are accessible from Python as r.variable.
Document metadata and citations
Quarto integrates with BibTeX and CSL (Citation Style Language) for academic citations. Add a bibliography file to the YAML: bibliography: references.bib. Cite with [@key] for parenthetical citations and @key for narrative citations. csl: apa.csl selects the citation style.
Zotero integration: RStudio’s visual editor shows a “Citation” insert dialog that searches your Zotero library and inserts citations and bibliography entries automatically. This eliminates manual BibTeX entry management.
The crossref section in YAML customizes cross-reference labels: crossref: fig-prefix: "Figure" changes the default “fig.” prefix. Equations, theorems, and lemmas are also cross-referenceable in Quarto with appropriate prefixes.
Rendering Quarto documents
quarto::quarto_render("document.qmd") renders from R. The quarto CLI: quarto render document.qmd from the terminal. RStudio provides a “Render” button for .qmd files. VSCode with the Quarto extension adds the same button.
The rendering pipeline: knitr (or Jupyter for Python) executes the code chunks and produces a .md file with all outputs embedded. Pandoc then converts the markdown to the target format. Understanding this two-step process helps when debugging rendering errors, check whether the problem is in the code execution step or the pandoc conversion step.
For R-heavy documents, knitr::knit("doc.qmd", output = "doc_processed.md") runs just the knitr step, producing markdown with executed code. Inspect the processed markdown to debug before attempting the full render.
Collaboration and version control
Quarto documents are plain text, making them suitable for version control. Code, prose, and configuration all live in one .qmd file. The rendered HTML or PDF output can be excluded from version control (add to .gitignore) to avoid merge conflicts on binary output files.
quarto check verifies the Quarto installation, available engines, and Knitr/Jupyter configuration. Run this first when debugging rendering issues on a new machine.
For teams, Quarto projects with shared _quarto.yml configuration enforce consistent output settings. The _freeze directory caches computation results so team members do not need to re-execute all code on every pull. execute-freeze: auto in _quarto.yml only re-executes chunks when their source code changes.
Embedding code from other files
knitr::read_chunk("helper.R") reads labeled chunks from an external R file and makes them available by label. This lets you separate long code into a separate .R file while displaying and executing it in the document. The external file uses ## ---- chunk-label ---- markers.
{{< include other.qmd >}} (Quarto shortcode) embeds another .qmd file’s content at the current location. Use this for shared sections, disclaimers, or boilerplate that appears in multiple documents. The included content renders in the context of the parent document.
knitr::read_chunk() combined with eval = FALSE in the chunk that reads the code lets you display code from an external file without executing it, useful for documentation that shows example code without running it.
The rendering pipeline in depth
Understanding how Quarto renders documents helps when debugging and when optimizing render times. The pipeline has two distinct phases.
In the execution phase, knitr (for R) or Jupyter (for Python) runs the code chunks and produces a standard Markdown document with all outputs embedded. Code chunk outputs, printed values, plots, tables — are converted to appropriate Markdown representations. Plots become image files referenced in the Markdown. Data frames become Markdown tables or HTML tables depending on the output format.
In the conversion phase, Pandoc converts the Markdown to the target format. Pandoc is a universal document converter that handles dozens of input and output formats. For HTML output, it generates HTML with CSS. For PDF, it generates LaTeX which a LaTeX engine then typeset. For Word, it generates DOCX. Pandoc’s versatility is why a single Quarto document can produce so many different output formats.
This two-phase design means you can debug each phase independently. If a plot fails, the error is in the execution phase. If a heading renders incorrectly in the output, the problem is likely in the Pandoc conversion phase or in document-specific formatting options.
Inline code as documentation
The practice of using inline R code for numbers in prose — writing the R expression that computes the number rather than the number itself — is one of the most valuable features of R Markdown and Quarto for data analysis. It makes the document self-updating: change the data, re-render, and every number in the prose is automatically correct.
This practice also serves as documentation. When a reader sees a formatted number in a report, they cannot know whether it was computed or typed manually. When the number is an inline R expression, the computation is explicit and auditable. Statistical reports written in Quarto with inline code are more transparent and reproducible than reports where numbers were manually entered.
The workflow implication is that you should compute all numbers reported in prose from the data, not hard-code them. Create named R objects for key figures (total sample size, primary outcome mean, model coefficient) and reference those objects in inline code. This discipline prevents the common error of updating a table or figure but forgetting to update the corresponding number in the text.
How Quarto processes documents
Quarto works in two stages. First, the source file is processed by knitr (for R code) or Jupyter (for Python/Julia), which executes code chunks and replaces them with their output. The result is a plain Markdown file with output embedded. Second, Pandoc converts that Markdown to the target format. Understanding this two-stage process helps when debugging: if output looks wrong, check whether the problem is in the execution stage or the Pandoc rendering stage.
Code chunk output is embedded as images for plots or text blocks for printed output. The chunk options control what appears: hiding the code but showing output, showing the code but not running it, or running the code silently with no output shown. These options can be set globally in the document YAML header and overridden per-chunk, which is the typical pattern — set sensible defaults at the top and override where needed.
YAML header structure
The document YAML header controls document-level behavior. The format key specifies the output format and accepts nested options. For HTML output, options like collapsible code, a table of contents, and theme choice are nested under the html key. Different formats accept different options — PDF output takes LaTeX document class and geometry settings, while Word output takes a reference document path for applying a template.
The execute block in the YAML header sets global chunk execution options. Enabling caching means code that has not changed is not re-run. Caching speeds up iterative development significantly for chunks that do database queries or slow computations. The cache is stored in a directory next to the source document.
Tables and figures
Quarto renders data frames as formatted HTML tables in HTML output. The default rendering is minimal. Setting the df-print option to kable in the YAML header renders data frames with knitr’s kable formatter, producing clean bordered tables. For more control, use the gt, kableExtra, or reactable packages to create formatted tables within code chunks.
Figures get captions and cross-references through chunk options. Adding a fig-cap option attaches a caption, and adding a label starting with “fig-” makes the figure cross-referenceable. In text, reference it with the at-sign prefix, which becomes “Figure 1” with a hyperlink in HTML output and a proper figure reference in PDF. Figure dimensions are set in chunk options in inches and can be set globally for consistent sizing across all figures in a document.
Rendering workflow
Render a Quarto document from RStudio with the Render button, or from the terminal with the quarto render command followed by the file name. Specifying a format with the —to flag overrides the format in the YAML header. This is useful for generating multiple output formats from one source file as part of a build script.
Quarto projects group multiple documents with a shared configuration file. The project configuration sets options that apply to all documents in the project, like a shared bibliography, consistent output directory, and navigation structure for websites. Projects also support rendering all documents at once, which is how Quarto websites and books are built.
Next steps
You now know the basics of Quarto. From here, explore these areas:
- Parameterized reports that rerun with new data by defining parameters in the YAML
- Quarto websites and blogs for publishing online with the
quarto publishcommand - Jupyter integration for Python workflows and data science projects
- Custom formatting with Lua filters for advanced document customization
- GitHub Actions for automated document building and deployment
Quarto’s documentation at quarto.org/docs covers these topics in depth. Start with your own documents and experiment with the options that fit your workflow.
See also
- Quarto Guide — Comprehensive reference for Quarto publishing including advanced output formats and project configuration.
- Quarto Dashboards — Build interactive dashboards directly from Quarto documents.
- Getting Started with R — Master R fundamentals before building Quarto documents.
- ggplot2 Charts — Create publication-quality figures to embed in your Quarto reports.
- String Manipulation with stringr — Clean and prepare text data for your Quarto documents.