← Back to blog

Forme is now on crates.io

The Rust PDF engine that powers Forme is now available as forme-pdf on crates.io. Use the layout engine and PDF writer directly from Rust — cargo add forme-pdf.

The Forme rendering engine has always been written in Rust. It powers the WASM builds, the self-hosted server, and the VS Code extension. But until now, the only way to use it from Rust was to clone the repo and depend on a path.

forme-pdf is now on crates.io.

What you get

cargo add forme-pdf
use forme::{render_json, FormeError};

fn main() -> Result<(), FormeError> {
    let json = r#"{
        "pages": [{ "size": "A4" }],
        "children": [{
            "kind": "text",
            "content": "Hello from Forme!",
            "style": { "fontSize": 24, "margin": { "top": 72, "left": 72 } }
        }]
    }"#;

    let pdf_bytes = render_json(json)?;
    std::fs::write("hello.pdf", pdf_bytes).unwrap();
    Ok(())
}

The crate is published as forme-pdf (because forme was taken on crates.io), but the library name is forme — so your use statements are use forme::render_json, use forme::Document, etc.

The full engine, not a wrapper

This isn't a thin client for a hosted API. It's the actual layout engine: flexbox distribution, page-aware line breaking, font subsetting, PDF serialization — all running natively. The same code that runs in the browser via WASM and in the self-hosted server via Axum.

What's included:

  • Page-native layout — every layout decision respects page boundaries. No infinite-canvas-then-slice.
  • Flexbox — row, column, wrap, grow/shrink, all alignment modes, cross-axis stretch
  • CSS Grid — track sizing, auto/explicit placement, repeat() syntax
  • Text — OpenType shaping (rustybuzz), Knuth-Plass line breaking, hyphenation in 35+ languages, BiDi (UAX#9), per-character font fallback with builtin Noto Sans
  • Tables — automatic header repetition on continuation pages
  • Images — JPEG, PNG, WebP
  • Charts — BarChart, LineChart, PieChart, AreaChart, DotPlot rendered as PDF vector graphics
  • QR codes & barcodes — Code128, Code39, EAN13, EAN8, Codabar
  • SVG — rect, circle, line, path (including arcs)
  • Tagged PDF, PDF/UA-1 and PDF/A-2 — accessibility and archival compliance, veraPDF-verified since 0.15.0 (UA) and 0.16.0 (A); output from versions before those did not validate
  • Templates — expression language ($ref, $each, $if, comparisons, arithmetic) for dynamic documents
  • Embedded data — attach JSON inside the PDF, extract it later

Two entry points

JSON — parse a JSON document and render:

let pdf = forme::render_json(json_str)?;

Structs — build a Document directly:

use forme::{Document, Node, NodeKind, Style, PageConfig, PageSize, render};

let doc = Document {
    children: vec![Node {
        kind: NodeKind::Text { content: "Hello".into() },
        style: Some(Style { font_size: Some(24.0), ..Default::default() }),
        ..Default::default()
    }],
    pages: vec![PageConfig { size: Some(PageSize::A4), ..Default::default() }],
    ..Default::default()
};

let pdf = render(&doc)?;

Both return Result<Vec<u8>, FormeError>. The _with_layout variants also return a LayoutInfo struct with the position and dimensions of every element on every page.

Templates

For server-side rendering without a JavaScript runtime, use the template system:

let template = r#"{ "children": [{ "kind": "text", "content": { "$ref": "name" } }] }"#;
let data = r#"{ "name": "Jane Smith" }"#;
let pdf = forme::render_template(template, data)?;

Templates support $ref (data access), $each (iteration), $if (conditionals), comparisons, arithmetic, string operations, and $format (number formatting). The expression evaluator runs in Rust — no JavaScript needed.

WASM compilation

The crate compiles to WebAssembly. This is how @formepdf/core works — the same engine, compiled to WASM via wasm-pack:

[dependencies]
forme-pdf = { version = "0.7", features = ["wasm"] }

The wasm-raw feature provides C-ABI exports for non-JS WASM hosts (Python via wasmtime, Go via wazero).

Install

cargo add forme-pdf

API docs on docs.rs | Full documentation | GitHub