Using Typst from other languages
In many cases, you'll want to use Typst in a specific workflow, which often means using a programming language. Whether it's Python, Rust, JavaScript or R, Typst will work seamlessly.
Bindings¶
In software, bindings are the "glue" that let code written in one programming language be used from another language.
They expose functions, classes, or libraries from one language/runtime to another by handling things like:
- Type conversion (e.g., Rust types ↔ Python objects)
- Memory management
- Calling conventions
- Error handling translation
Example: Rust + Python with maturin¶
maturin helps you create Python bindings for Rust code.
What happens conceptually:
- You write performance-critical logic in Rust.
- You expose selected Rust functions using a binding layer (commonly via
pyo3). maturinbuilds a Python extension module from that Rust code.- Python can then import and use it like a normal module.
So instead of rewriting performance-sensitive code in Python, you:
- Keep speed in Rust
- Access it from Python via bindings
Simple Conceptual Example¶
Rust:
After building with maturin, Python can do:
Here, the binding layer:
- Converts Python integers Rust
i32 - Calls the Rust function
- Converts the result back Python integer
Why bindings exist¶
- Performance (C/C++/Rust libraries used in Python, Ruby, etc.)
- Reusing existing libraries
- Accessing system-level APIs
- Interoperability between ecosystems
Typst bindings¶
In the context of Typst, this is very useful because it lets us use our current logic to define the output report.
Since Typst is built using Rust, we can easily find bindings for many programming languages. In particular, since Typst can be used as a Rust library, people can use that library and build on top of it. Right now, the simplest way to use Typst in Rust is via the typst-as-lib library, which is a community-made tool.
This means that all bindings rely on the Typst library (e.g., Rust) to use Typst, no matter the programming language.
graph LR
A[Typst compiler] --> B{Typst Rust library};
B -->|Python| C[Python to Rust bindings];
C --> G{Python};
B -->|R| D[R to Rust bindings];
D --> H{R};
B -->|JavaScript| E[JS to Rust bindings];
E --> I{JavaScript};
B -->|Rust| F{Rust};
This also means that using Typst from Rust is more "native" than in other programming languages since it does not require bindings. You can learn about that in the Typst from Rust post, or choose your favorite programming language: