Typst: Designing for Incrementality

Lobsters Hottest Products

Summary

Typst uses constrained memoization (comemo) and pure function design to make the language and compiler work together, achieving efficient incremental compilation and real-time preview. The article details the design ideas of layout caching, module evaluation memoization, function purity, and the introspection system.

<p><a href="https://lobste.rs/s/hj0exw/typst_designing_for_incrementality">Comments</a></p>
Original Article
View Cached Full Text

Cached at: 06/29/26, 04:31 PM

TL;DR: Typst achieves efficient incremental compilation and real-time preview through constraint memoization (comemo) and a pure function design, making the language and compiler work together. ## Introduction: Typst's Design Goals Typst is a markup-based typesetting system with its own markup language, styling system (`set` and `show` rules), a full scripting layer, and an introspection system. It is designed to be easy to learn and pleasant to use, with the core goal of achieving **real-time preview**—entirely feasible given 2026's hardware. The key is to **co-design the language and its implementation** to support high-performance incremental compilation. ## The Core of Incremental Compilation: Memoization To reuse already compiled results when editing a document, Typst uses **memoization** to remember intermediate compilation results. ### Simple Memoization of Layout A layout function takes inputs like a paragraph and a width and returns a fixed-sized frame. It is a pure function with no side effects. So simply hash the inputs (using `xxhash`) and store the result in a hash map. This is the most basic caching strategy, and it is remarkably effective in reducing layout overhead. ### Module Evaluation and Constraint Memoization The scripting system includes modules, organized using `include` and `import`. If we memoize the `eval` function directly, its inputs include a source file and the filesystem. But the filesystem changes when external files change, causing all `eval` calls to be invalidated. Typst uses the **comemo** (constraint memoization) crate: the filesystem is wrapped in a `Tracked` type. Each time `eval` calls `fs.load`, it records the actual file path that was read and its hash, forming a set of “constraints”. After evaluation finishes, the constraints and output are stored together in the cache. On the next call, we hash the non-tracked arguments to find the entry, then check each constraint individually. The cache is invalidated only when an actually-read file changes, avoiding a full recompilation. ## Functions and Purity User functions in Typst must also be cacheable. The idea is to enforce **pure functions**—no mutable references, no global state. Does this turn the script language into Haskell? Not really. Typst is more like “deterministic Rust without references”, allowing local mutability (e.g., `for` loops), but mutability is encapsulated inside functions. Efficient data passing is achieved through value semantics and reference counting (`Arc`), without needing lifetimes. For example, when returning a vector, cloning into the cache only requires `arc_bump` (incrementing the reference count), offering great performance. Local mutability is implemented via `Arc::make_mut`: check if the reference is unique; if so, mutate in place; otherwise, clone then mutate. This design ensures cache correctness while keeping the script language easy to use. ## Challenges of a Typesetting System: Counters and Table of Contents Pure functions cannot directly use mutable counters (like section numbers) or query the internal state of the document (like a table of contents). Counters seem simple, but a table of contents and cross-references are actually two sides of the same coin: both require document introspection. ### LaTeX's Multiple Iterations LaTeX solves this by writing information to auxiliary files (e.g., `.toc`) and running the compiler multiple times. Users need to run repeatedly, using `latexmk` to automatically iterate until stable. This is a “keep retrying until convergence” approach. ### Typst's Introspection System Instead of relying on mutability, Typst provides **introspection** capabilities: the document can observe its own structure. For example, one can ask “where is the first heading in the document?” and obtain its page coordinates. In this way, symbolic numbering (like chapter numbers) and the table of contents can be implemented via introspection rather than mutable counters. This still respects the pure function constraint while solving traditional typesetting pain points in a more declarative manner. ## Summary Typst achieves efficient incremental compilation by tightly coupling the compiler's memoization features with a pure function language design. Layout caching, constraint-memoized module evaluation, enforced function purity, and the introspection system together form the foundation for Typst's real-time preview. This co-design approach allows the language syntax and implementation to reinforce each other, rather than becoming a burden. Source: https://youtu.be/yWWVhbyOWWE

Similar Articles

@seclink: Classic pitfall of sccache and incremental being mutually exclusive: enabling both results in 20GB of incremental cache yet dependencies being recompiled every time. After turning off incremental: large third-party libraries (tokio/serde/axum/reqwest, etc.) compile once, across…

X AI KOLs Following

Explains the mutual exclusivity issue between sccache and incremental compilation: enabling both leads to 20GB incremental cache consumption and dependencies being recompiled each time. After disabling incremental, large third-party libraries compile once and are reused across projects, achieving a cache hit rate of 53–93% after the first compilation.

@billtheinvestor: Give Claude Code and Codex infinite memory, programming efficiency improved by 92%! The Agentmemory tool has quickly gained 4000+ stars on GitHub and is completely free. It saves all information from your coding sessions through smart compression, and automatically extracts relevant context in future sessions, avoiding re...

X AI KOLs Timeline

Agentmemory is an open-source tool that provides infinite memory for Claude Code and Codex, reducing token usage through intelligent compression, improving programming efficiency, and has gained 4000+ stars on GitHub.

Gleam and the value of small

Lobsters Hottest

Gleam is a deliberately concise functional programming language that enhances readability and developer experience by reducing keywords and avoiding repetitions. Its design philosophy is 'less is more'.

Syntax with Purpose in a Programming Language

Lobsters Hottest

This article explores the importance of syntax design in programming languages, arguing that syntax should accurately reflect the language's computational model and mental model, rather than being arbitrarily cobbled together for familiarity or conciseness. The author analyzes the syntax design of OCaml, Lisp/Clojure, and JavaScript, and introduces his own language Saul, emphasizing uniformity and semantic consistency.

Introducing Incremental

Lobsters Hottest

Jane Street announces Incremental, a library for building self-adjusting computations that efficiently update when inputs change, applicable to online algorithms, GUI construction, and configurable computations.