This entire showcase image was generated with Typst – view the code
A fast, no-nonsense Node.js library for rendering Typst to PNG, JPEG, WebP, or PDF.
It uses the official Typst compiler through native Rust bindings (@myriaddreamin/typst-ts-node-compiler) and Sharp for rasterization, so you get near-native performance with pixel-perfect results. I built it because I needed a reliable way to generate crisp math equations and document snippets in backend services and bots, and nothing else quite cut it.
Comes with New Computer Modern fonts bundled, works out of the box on Lambda, Vercel, Docker, or anywhere else, no system font dependencies required.
- Native-speed compilation via direct Rust bindings
- SVG → raster pipeline with Sharp (sub-pixel accurate, any DPI)
- SVG output support for vector graphics
- Built-in caching (LRU, enabled by default)
- Batch rendering API for multiple renders
- Zero-config font setup (New Computer Modern Book included)
- Automatic tight cropping in snippet mode (perfect for equations)
- Full TypeScript support with proper types
- Variable injection, custom font paths, quality/scale control
- Metadata extraction from rendered images
- Stream output for efficient HTTP responses
- Tiny bundle size, no heavyweight dependencies
typst-raster offers a lightweight, all-in-one solution for rendering documents and equations, avoiding the complexity of installing system-level dependencies.
| Feature | typst-raster | System LaTeX (node-latex) | MathJax (mathjax-node) | Puppeteer (Headless Chrome) |
|---|---|---|---|---|
| Engine | Native Rust (Node Bindings) | System Binary (pdflatex) | JavaScript | Chromium Browser |
| Prerequisites | None (npm install only) | Heavy (Requires TeXLive) | None | Chromium Binary |
| Install Size | ~8.9 MB | 2GB - 4GB | ~50 MB | ~280 MB+ |
| Speed | Fast (Native compilation) | Slow (Spawns process) | Medium | Very Slow (Browser startup) |
| Output | PDF, PNG, JPEG, SVG, WEBP | PDF only | SVG/HTML only | PDF, PNG |
| Serverless | ✅ Ready (Fonts included) | ❌ Difficult (Too large) | ✅ Ready | |
| Scope | Full Documents + Math | Full Documents + Math | Math Equations Only | Webpages |
1. No external dependencies required Running standard LaTeX wrappers in Node.js usually requires installing a full TeX distribution (like TeXLive) on the host machine. This is often impossible on managed hosting platforms like Vercel or standard shared hosting. This package runs entirely within Node.js with no external requirements.
2. Solves the missing font issue Generating PDFs or images on cloud functions (AWS Lambda, Google Cloud) often results in broken text because the environments lack standard fonts. This package bundles high-quality fonts internally, ensuring documents render correctly on any server without manual configuration.
3. Direct conversion to multiple formats
Most alternatives specialize in one output format. LaTeX tools output PDF; MathJax outputs SVG. typst-raster handles the full pipeline internally, allowing you to generate PDFs for reports or PNGs for web previews using a single library. This removes the need for additional conversion tools like ImageMagick.
npm install typst-rasterimport { Typst } from 'typst-raster';
import { writeFile } from 'fs/promises';
const renderer = new Typst();
const buffer = await renderer.render({
code: '= Hello from Typst!\nThis is a quick test of the renderer.',
});
await writeFile('hello.png', buffer);const buffer = await renderer.render({
code: '$ sum_(k=1)^n k = (n(n+1))/2 $',
snippet: true, // auto-crop to content
scale: 3, // 3× resolution for retina displays
format: 'png',
});const buffer = await renderer.render({
code: 'Hello #sys.inputs.name, welcome to #sys.inputs.project!',
variables: {
name: 'Alice',
project: 'typst-raster',
},
});const buffer = await renderer.render({
code: '$ E = m c^2 $',
snippet: true,
backgroundColor: 'white',
});const myTheme = `
#set page(fill: rgb("#2b2d31"), margin: 1cm)
#set text(fill: white, font: "Roboto")
`;
const buffer = await renderer.render({
preamble: myTheme,
code: '$ sum_(k=1)^n k = (n(n+1))/2 $',
snippet: true,
});const buffer = await renderer.render({
code: '= Document Title\n\nThis is a *PDF* document.',
format: 'pdf',
});
await writeFile('document.pdf', buffer);const buffer = await renderer.render({
code: '$ E = mc^2 $',
format: 'svg',
snippet: true
});
await writeFile('equation.svg', buffer);const results = await renderer.renderBatch([
{ code: '$ a^2 + b^2 = c^2 $', snippet: true },
{ code: '$ \\int_0^\\infty e^{-x} dx = 1 $', snippet: true },
{ code: '$ \\sum_{n=1}^\\infty \\frac{1}{n^2} = \\frac{\\pi^2}{6} $', snippet: true }
]);
// Save all results
for (let i = 0; i < results.length; i++) {
await writeFile(`equation-${i}.png`, results[i]);
}import { getMetadata } from 'typst-raster';
const buffer = await renderer.render({
code: '$ x^2 $',
snippet: true,
ppi: 300
});
const metadata = await getMetadata(buffer);
console.log(`Dimensions: ${metadata.width}x${metadata.height}`);
console.log(`Format: ${metadata.format}`);
console.log(`DPI: ${metadata.density}`);import { createWriteStream } from 'fs';
const stream = await renderer.renderStream({
code: '$ \\frac{-b \\pm \\sqrt{b^2 - 4ac}}{2a} $',
format: 'png',
snippet: true
});
stream.pipe(createWriteStream('equation.png'));
// Or in Express/Fastify:
// stream.pipe(res);// Disable cache entirely
const renderer = new Typst({ cache: false });
// Or customize cache size
const renderer = new Typst({ cacheSize: 500 }); // default: 100For more details, visit the Documentation Site.
new Typst(options?: {
fontPath?: string; // folder with additional .ttf/.otf files
})renderer.render(options): Promise<Buffer>| Option | Type | Default | Description |
|---|---|---|---|
code |
string |
— | Required Typst source |
format |
'png' | 'jpeg' | 'webp' | 'pdf' |
'png' |
Output format |
quality |
number (1–100) |
100 |
JPEG/WebP quality (ignored for PDF) |
ppi |
number |
192 |
Raster resolution (ignored for PDF) |
scale |
number |
1 |
Additional multiplier (ignored for PDF) |
snippet |
boolean |
false |
Crop tightly to content (great for equations) |
variables |
Record<string, string | number | boolean> |
{} |
Injected as #sys.inputs.key |
backgroundColor |
string |
— | Flatten transparency (raster only) |
preamble |
string |
— | Typst code prepended to every render |
The library exports a TypstRenderError class that you can catch to handle rendering failures specifically.
import { Typst, TypstRenderError } from 'typst-raster';
try {
await renderer.render({ code: '#invalid()' });
} catch (error) {
if (error instanceof TypstRenderError) {
console.error('Typst compilation failed:', error.message);
}
}Huge thanks to the projects this wouldn't exist without:
- Typst – the reason we're all here
- @myriaddreamin/typst.ts – incredible compiler and Node.js bindings
- Sharp – the fastest image library there is
- New Computer Modern – beautiful default fonts
MIT © 2025 RayZ3R0