What is Typst?

Typst is an open-source typesetting system designed specifically for creating documents. It was created by Laurenz Mädje as his Master's thesis at TU Berlin in 2019 and publicly released in 2023. The project is written in Rust and licensed under Apache 2.0.

Like LaTeX, Typst takes a markup source file and compiles it into a PDF. Unlike LaTeX, it was designed from the ground up with modern software engineering practices: a single-pass incremental compiler, meaningful error messages, a clean scripting language, and a consistent, predictable syntax.

A minimal Typst document looks like this:

hello.typ
#set page(paper: "a4", margin: 2cm) #set text(font: "Inter", size: 11pt) #align(center)[ = Hello, World! _A Typst document._ ] Regular paragraph text uses markup that feels like Markdown. *Bold text* and _italic text_ work as expected. Mathematical formulas: $ E = m c^2 $

The # prefix indicates a Typst function call or keyword. The square brackets [...] delimit content blocks. Everything outside content blocks is regular text with Markdown-like formatting conventions. This is fundamentally cleaner than LaTeX's backslash-command style.

Typst vs LaTeX: the key differences

LaTeX has been the standard for academic and scientific publishing since 1984. It produces beautiful output and has a massive package ecosystem built over four decades. But its age shows.

FeatureLaTeX (pdfLaTeX/XeLaTeX)Typst
Compilation speed5–30s, multiple passes100–500ms, single pass
Error messagesCryptic, line numbers offClear, actionable, highlighted
Syntax clarityBackslash commands everywhereClean, consistent # prefix
Live previewRequires latexmk + viewerBuilt-in, instant rerender
Math supportComprehensive (decades of packages)Good and growing fast
Scripting / variablesMacros (complex, error-prone)First-class functions and types
Package ecosystemCTAN: 6,000+ packagesGrowing: 1,200+ packages
Bibliography supportBibTeX, Biblatex (mature)Built-in Hayagriva
Open sourceYes (LPPL)Yes (Apache 2.0)
API-suitableNo (too slow, stateful)Yes (designed for it)

The compilation speed difference matters enormously for APIs

LaTeX's multi-pass compilation model was designed for documents where cross-references, table of contents, and bibliographies need multiple rendering passes to be consistent. For a 50-page academic paper, this is fine — you compile it once. For an API that generates PDFs on-demand, a 10-second compile per request makes the service unusable.

Typst's incremental compiler is stateless and single-pass. It tracks which parts of the document changed and only recompiles those sections. In the context of a PDF API, this means generating a new invoice from a template and JSON data takes 200–400ms from template compilation to binary PDF output — including the rendering step.

Error messages: a major quality-of-life difference

If you've written LaTeX, you've encountered something like this:

Typical LaTeX error
! Undefined control sequence. l.47 \makettle {My Document Title} ?

The line number is often off by 20 lines from the actual problem due to macro expansion. Typst errors are designed like modern compiler errors:

Equivalent Typst error
error: unknown variable: makettle --> document.typ:47:2 | 47 | #makettle("My Document Title") | ^^^^^^^^ not found in scope | = did you mean: make-title?

This matters for template authors and for debugging in production systems where you need to understand why a PDF failed to render.

Typst vs HTML/CSS PDF tools

The most popular way to generate PDFs today is to render HTML/CSS with a headless browser (Puppeteer, Playwright) or a dedicated HTML-to-PDF engine (wkhtmltopdf, Prince). These tools work, but they carry significant overhead.

HTML and CSS were designed for interactive web pages rendered on variable-size screens. Every CSS property that makes sense for a webpage (scrolling, hover effects, media queries for screen widths) is overhead when generating a static document. The browser has to lay out the page, apply all CSS, run JavaScript, and then print it — a process designed for real-time interactive rendering, not batch document generation.

Typst knows it is creating a document from the start. Its layout engine handles pagination, hyphenation, widow and orphan control, running headers and footers, and cross-references as first-class features. These are features you fight CSS to implement; in Typst they are simple declarations.

Typography features that are hard in CSS, trivial in Typst
// Running headers with section title #set page(header: context [ #set text(size: 9pt, fill: gray) _My Report_ #h(1fr) Chapter #counter(heading).display() ]) // Automatic page numbers in footer #set page(footer: context align(center)[ counter(page).display("1 of 1", both: true) ]) // Widow/orphan control — no orphaned headings #set block(breakable: false) // for headings // Justified text with proper hyphenation #set par(justify: true, leading: 0.8em)

Typst vs Markdown

Markdown is the simplest option for writing structured text. It converts to HTML easily and many tools can render it to PDF via an HTML intermediate step. But Markdown has hard limits for document design:

Typst supports Markdown-like writing syntax for the body text (headings with =, *bold*, _italic_) while adding full design capabilities. You get the authoring simplicity of Markdown with the power of a professional typesetting system.

Basic Typst syntax examples

Understanding Typst syntax is important if you want to write custom templates for Typsetter. Here are the most common patterns:

Typst syntax: text formatting
// Headings (like Markdown) = Heading 1 == Heading 2 === Heading 3 // Emphasis *Bold text* _Italic text_ `Monospace text` // Lists - Unordered item + Ordered item + Nested ordered item // Links #link("https://typsetter.dev")[Typsetter] // Images #image("logo.png", width: 40%)
Typst syntax: tables
#table( columns: (1fr, 2fr, auto), stroke: (x, y) => if y == 0 { 1pt + black } else { 0.5pt + gray }, table.header[Service][Description][Amount], [Web Dev], [Homepage redesign], [$4,500], [SEO], [Technical audit], [$1,200], )
Typst syntax: variables and functions (scripting)
// Define and use variables #let company_name = "Acme Corp" #let tax_rate = 0.2 #let subtotal = 5700 #let tax = subtotal * tax_rate #let total = subtotal + tax // Display variable Billing to: #company_name // Conditional logic #if tax_rate > 0 [ Tax (#(tax_rate * 100)%): #tax ] Total due: #total // Define a reusable function #let badge(text, color: blue) = box( fill: color.lighten(80%), radius: 4pt, inset: (x: 6pt, y: 3pt) )[#set text(fill: color.darken(20%)); #text] #badge("Paid", color: green) #badge("Overdue", color: red)

Advanced features: what makes Typst powerful for APIs

Content functions and higher-order programming

Typst's scripting model supports functions that accept content as arguments, closures, and higher-order functions. This enables building document component libraries — a card() function that renders a styled card, an invoice_row() that renders a table row with computed totals, and so on. These compose to create complex documents from simple data structures.

State and counters

Typst provides mutable state that can be read and updated during document layout. This powers automatic numbering (figure numbers, footnote counts, section numbering) and running totals (cumulative amounts in a financial statement).

Custom page layouts

Typst supports variable-height pages (the PDF height adjusts to fit the content), multi-column layouts, rotated content, and complex grid arrangements. For a receipt that might be 8cm or 80cm tall depending on the number of line items, this is essential.

Why this matters for Typsetter specifically

Typsetter's template engine works by layering Tera templating on top of Typst. Before Typst compiles your template, the Tera engine substitutes all {{ variable }} placeholders with values from your JSON request body. Tera also handles autoescape (preventing injection of malicious Typst code through user data), loops over array fields ({% for item in line_items %}), and conditional blocks ({% if tax_rate > 0 %}).

This means template authors write Typst once with Jinja2-style placeholders, and Typsetter handles the data substitution, escaping, and rendering pipeline. You get the full power of Typst without needing to know Rust or run Typst locally.

Typst in the context of PDF APIs

Before Typst, the options for a PDF generation API were:

  1. Spawn a headless Chrome per request (4+ seconds, 300MB RAM per instance)
  2. Spawn wkhtmltopdf per request (2-3 seconds, deprecated)
  3. Run a LaTeX compilation per request (10-30 seconds, absolutely not)
  4. Use a proprietary PDF library like iText or PDFKit (no template system, programmatic layout only)

Typst changed this. Its stateless, single-pass compilation takes 200-500ms for a typical document. Its scripting language is expressive enough to model any document layout. And it is open source with an Apache 2.0 license, which means a company can embed it in a product without licensing concerns.

Typsetter is built specifically around this opportunity: Typst as the rendering engine, Tera as the template substitution layer, and Axum (Rust HTTP framework) as the API layer. The result is a PDF generation service that is genuinely fast rather than "fast enough."

Open Source

Typst is fully open source at github.com/typst/typst. You can run Typst locally, contribute to the project, and use it freely in any application. The Typsetter service wraps Typst in a managed API with templates, batch processing, and integrations on top.

Getting started with Typst

If you want to write custom Typst templates for Typsetter:

  1. Install Typst locally: cargo install typst-cli (requires Rust) or download from GitHub releases
  2. Start with the official documentation at typst.app/docs
  3. Browse the Typst Universe (package registry) at typst.app/universe
  4. In Typsetter, create a new template, switch to the code editor, and paste your Typst source — then add Tera variables where you want JSON data substituted

For teams that don't want to learn Typst, Typsetter's 31 starter templates cover the most common document types out of the box, and the visual editor handles layout without any markup.

Build your first Typst-powered PDF

Typsetter makes Typst accessible as a REST API. No Rust, no local setup, no binary to manage — just send JSON, get a PDF.