Skip to content

Typst vs LaTeX for Math Rendering: A Python Developer's Perspective

When I needed to render mathematical formulas in PDFs from Python, I assumed LaTeX was the only professional option. After spending hours debugging cryptic LaTeX errors and struggling with verbose syntax, I discovered Typst - a modern alternative that produces the same quality output with much cleaner syntax.

The Problem

I was building a scientific report generator for a research team. The reports needed complex mathematical expressions - partial derivatives, integrals, matrices, and equations with various formatting requirements.

I started with LaTeX, the standard for mathematical typesetting. Here’s what a partial derivative looked like:

partial_derivative.tex
\frac{\partial f}{\partial x} = \lim_{h \to 0} \frac{f(x+h) - f(x)}{h}

To render this from Python, I needed a full LaTeX installation plus a Python wrapper:

latex_renderer.py
import subprocess
import tempfile
import os
def render_latex_equation(latex_code, output_path):
"""Render LaTeX equation to PDF using pdflatex."""
doc = f"""
\\documentclass{{article}}
\\usepackage{{amsmath}}
\\begin{{document}}
\\[
{latex_code}
\\]
\\end{{document}}
"""
with tempfile.TemporaryDirectory() as tmpdir:
tex_file = os.path.join(tmpdir, 'equation.tex')
with open(tex_file, 'w') as f:
f.write(doc)
# Run pdflatex
result = subprocess.run(
['pdflatex', '-interaction=nonstopmode', tex_file],
cwd=tmpdir,
capture_output=True,
text=True
)
if result.returncode != 0:
# Parse cryptic LaTeX error
print("LaTeX Error:")
print(result.stderr[-500:]) # Last 500 chars of error
return False
# Copy PDF to output
pdf_file = os.path.join(tmpdir, 'equation.pdf')
os.rename(pdf_file, output_path)
return True

I ran this and got:

Terminal window
$ python latex_renderer.py
LaTeX Error:
! Undefined control sequence.
l.5 \parital
{f}{x}
?

A typo in my macro name caused an error. The error message was cryptic - it pointed to \parital but didn’t explain the issue clearly. I spent 20 minutes debugging before realizing I had misspelled \partial.

The Core Pain Points

After a week of working with LaTeX, I identified these issues:

1. Verbose Syntax

Even simple fractions require backslashes and braces:

% A simple fraction in LaTeX
$\frac{a + b}{c + d}$
% Nested fractions get messy
$\frac{\frac{1}{x}}{\frac{y}{z}}$

2. Cryptic Error Messages

When I forgot a brace:

Terminal window
! Missing } inserted.
<inserted text>
}
l.15 \frac{a + b}{c + d
$
?

The error pointed to line 15, but the actual missing brace was somewhere else entirely.

3. Slow Compilation

Generating a PDF with 50 equations took 3-5 seconds. For a web service generating thousands of reports, this was too slow.

4. Heavy Dependencies

A full LaTeX installation is 3-5 GB. My Docker images ballooned in size.

Discovering Typst

I found Typst while searching for LaTeX alternatives. Typst is a modern typesetting system designed to be:

  • Faster: Compiles documents in milliseconds
  • Simpler: Cleaner syntax without sacrificing power
  • Integrated: Works as a library, not just a standalone program

Here’s the same partial derivative in Typst:

partial_derivative.typ
(partial f) / (partial x) = lim_(h -> 0) (f(x+h) - f(x)) / h

Notice the differences:

  • No backslashes for common operations
  • Parentheses instead of braces (more readable)
  • Underscore for subscripts (intuitive)
  • Fractions use / operator

Side-by-Side Comparison

Let me show common mathematical expressions in both syntaxes:

Fractions

fractions.tex
% LaTeX
$\frac{1}{x + 1}$
fractions.typ
// Typst
$ 1 / (x + 1) $

Matrices

matrix.tex
% LaTeX
$\begin{pmatrix}
1 & 2 \\
3 & 4
\end{pmatrix}$
matrix.typ
// Typst
$ mat(
1, 2;
3, 4
) $

The Typst version uses semicolons for row separation - much clearer than \\.

Piecewise Functions

piecewise.tex
% LaTeX
$f(x) = \begin{cases}
1 & \text{if } x \geq 0 \\
-1 & \text{if } x < 0
\end{cases}$
piecewise.typ
// Typst
$ f(x) = cases(
1 "if" x >= 0,
-1 "if" x < 0
) $

Typst uses cases() function with comma separation - easier to read and write.

Integrals

integral.tex
% LaTeX
$\int_0^\infty e^{-x^2} \, dx = \frac{\sqrt{\pi}}{2}$
integral.typ
// Typst
$ integral_0^infinity e^(-x^2) dif x = sqrt(pi) / 2 $

Typst uses named functions (integral, infinity) instead of symbols (\int, \infty). More typing, but more readable.

Greek Letters

greek.tex
% LaTeX
$\alpha, \beta, \gamma, \delta, \epsilon, \theta, \lambda, \mu, \pi, \sigma, \omega$
greek.typ
// Typst
$ alpha, beta, gamma, delta, epsilon, theta, lambda, mu, pi, sigma, omega $

Same letters, but no backslashes. Typst recognizes Greek letter names directly in math mode.

Chemistry

chemistry.tex
% LaTeX
$\text{H}_2\text{O}$ and $\text{NaCl}$
chemistry.typ
// Typst
$ "H"_2"O" "and" "NaCl" $

Typst uses quotes for text within math mode.

Using Typst from Python

The real win comes when integrating with Python. GoPdfSuit provides native Typst support:

typst_pdf.py
from pypdfsuit import PdfGenerator
template = {
"elements": [
{
"type": "math",
"content": "integral_0^infinity e^(-x^2) dif x = sqrt(pi) / 2",
"syntax": "typst"
},
{
"type": "text",
"content": "The Gaussian integral is a fundamental result in calculus.",
"style": {"font": "Helvetica", "size": 12}
},
{
"type": "math",
"content": """
f(x) = cases(
1 "if" x >= 0,
-1 "if" x < 0
)
""",
"syntax": "typst"
}
]
}
generator = PdfGenerator(template=template)
generator.render({}, "math_document.pdf")

I ran a comparison benchmark:

benchmark.py
import time
from pypdfsuit import PdfGenerator
# Generate 100 PDFs with 10 equations each
def benchmark_typst():
equations = [
"integral_a^b f(x) dif x",
"sum_(i=1)^n i^2 = n(n+1)(2n+1)/6",
"lim_(x -> 0) sin(x)/x = 1",
# ... more equations
]
template = {
"elements": [
{"type": "math", "content": eq, "syntax": "typst"}
for eq in equations
]
}
start = time.time()
for i in range(100):
generator = PdfGenerator(template=template)
generator.render({}, f"output_{i}.pdf")
end = time.time()
return end - start
print(f"Typst: {benchmark_typst():.2f}s for 100 PDFs")
# Output: Typst: 2.34s for 100 PDFs

The same benchmark with LaTeX via subprocess:

Terminal window
$ python latex_benchmark.py
LaTeX: 15.67s for 100 PDFs

Typst was 6-7x faster.

Why This Matters

The cleaner syntax and faster compilation changed my workflow:

Before (LaTeX):

  1. Write equation with verbose syntax
  2. Run compiler
  3. Parse cryptic error message
  4. Fix typo or missing brace
  5. Repeat 2-4 until working
  6. Wait for slow compilation

After (Typst):

  1. Write equation with intuitive syntax
  2. Get immediate output (or clear error)
  3. Done

The readability also improved code reviews. Team members could quickly scan equations and understand what they represent without mentally parsing backslashes and braces.

When LaTeX Still Wins

Typst is not a complete replacement. LaTeX still excels for:

1. Established Document Classes

If you need IEEE, ACM, or specific journal templates, LaTeX has decades of established classes. Typst’s ecosystem is newer.

2. Complex Bibliographies

BibTeX and its variants are deeply integrated into academic workflows. Typst has bibliography support, but it’s less mature.

3. Institutional Requirements

Some universities and journals require LaTeX source files. You can’t submit Typst.

4. Community Packages

LaTeX has thousands of packages for specialized needs. Want to typeset music scores? There’s musixtex. Chess diagrams? skak. Typst’s package ecosystem is growing but smaller.

Migration Tips

If you’re moving from LaTeX to Typst, here’s what I learned:

Start with new documents

Don’t try to convert existing LaTeX files. The syntax is different enough that manual rewriting is faster than conversion tools.

Learn the function names

Typst uses named functions for symbols:

LaTeXTypst
\intintegral
\inftyinfinity
\sumsum
\prodproduct
\sqrtsqrt
\partialpartial

Use the web app for learning

The Typst web app (typst.app) provides real-time preview. I wrote equations there first, then copied them to Python code.

Embrace the whitespace

Typst ignores whitespace in math mode (mostly), so you can format for readability:

// All equivalent
$ a+b $
$ a + b $
$ a + b $

Common Mistakes

1. Forgetting math mode delimiters

// WRONG - plain text
partial f / partial x
// CORRECT - math mode
$ partial f / partial x $

2. Missing parentheses in fractions

// WRONG - ambiguous
$ a / b + c $ // Means: (a/b) + c
// CORRECT - explicit
$ (a) / (b + c) $ // Means: a / (b + c)

3. Using LaTeX syntax

// WRONG - LaTeX syntax doesn't work
$ \frac{a}{b} $
// CORRECT - Typst syntax
$ a / b $

4. Not quoting text in equations

// WRONG - "if" is interpreted as variables i*f
$ f(x) = 1 if x >= 0 $
// CORRECT - quoted text
$ f(x) = 1 "if" x >= 0 $

Performance in Production

For the scientific report generator I mentioned earlier, switching from LaTeX to Typst:

MetricLaTeXTypst
Docker image size3.2 GB450 MB
PDF generation time (per doc)2.3s0.38s
Memory usage (peak)280 MB45 MB
Error rate4.2%0.3%

The error rate dropped dramatically because Typst’s error messages are actionable. When something goes wrong, I can actually fix it without trial and error.

Getting Started

To use Typst with Python:

Terminal window
# Install GoPdfSuit (includes Typst support)
pip install pypdfsuit
# Or install Typst directly
pip install typst

Basic usage:

hello_typst.py
import typst
# Direct compilation
typst.compile("document.typ", output="document.pdf")
# Or use GoPdfSuit for template-based generation
from pypdfsuit import PdfGenerator
generator = PdfGenerator(template={
"elements": [
{"type": "math", "content": "E = m c^2", "syntax": "typst"}
]
})
generator.render({}, "einstein.pdf")

For learning Typst syntax, the official documentation at typst.app/docs has excellent examples.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments