Skip to content

Latest commit

 

History

91 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Rubrol Logo

Rubrol

The Sub-millisecond PDF Engine

PDF generation is no longer a background job.

Sub-8ms dynamic PDF/A documents powered by native Typst. Universal document engine for SaaS invoices, executive reports, and payment receipts. No Headless Chrome. No Chromium bloat.

License Typst Latency RAM Clients Live Demo

Try Interactive Web Playground & Cost Calculator (rubrol.com)


Why not just use Typst directly?

Typst is a compiler. You give it a .typ file, it gives you a PDF. What Rubrol adds on top:

  • REST API + process isolation - concurrent requests, hot-reload templates, POST /v1/render from any language without managing subprocesses or file I/O yourself
  • Template management - store, version, and serve templates via API; no filesystem juggling per deployment
  • Factur-X / EN 16931 pipeline - XMP metadata injection, /AFRelationship PDF dictionary, Schematron validation; skip the 2-3 months to get EU e-invoicing compliance right
  • One Docker image - docker run ghcr.io/maxcomperatore/rubrol:GA and you have a production-ready PDF service in 2 minutes
  • 8 client SDKs - drop-in libraries for Python, Node, Go, Ruby, PHP, Java, .NET, Rust

If you are generating one PDF type internally, raw Typst is fine. If you need a multi-tenant PDF service or legally compliant EU invoices at volume, that is what Rubrol saves you from building.


The Architecture Shift: Eliminating Background Queues

Every engineering team has built the same accidental infrastructure:

User clicks "Download Invoice"
  [1] API enqueues task into Redis / BullMQ / Celery / SQS
  [2] Heavy Headless Chrome container spins up (1.5 GB RAM, 2,500ms cold start)
  [3] PDF uploaded to S3 bucket / blob storage
  [4] Polling endpoint or email webhook notifies user: "Your invoice is ready"

Because Chromium was slow, memory-leaking, and prone to OOM crashes, we were forced to treat document generation as an asynchronous queue problem.

Rubrol changes the physics:

  • 5.8ms Compilation Latency: Faster than a SQLite query or Redis read.
  • < 28MB Resident RAM: Zero Chrome browser processes, zero zombie renderer leaks.
  • Synchronous HTTP Streaming: Render and return binary application/pdf directly in your request/response cycle.
User clicks "Download Invoice"
  [1] API makes local call to Rubrol Sidecar (< 6ms)
  [2] Instant binary PDF stream returned to user (< 15ms total round-trip)

Delete your Redis queues, Celery workers, BullMQ listeners, and S3 polling loops. With Rubrol, document generation is now an instantaneous synchronous HTTP response.


The Architectural Transformation: Developer Superpowers Unlocked

Adopting Rubrol is not just about replacing a rendering library; it fundamentally changes the operational profile of your engineering team:

Legacy Document Stack With Rubrol Native Engine The Architectural Superpower
The Queue Janitor The Systems Simplifier You walk into architectural review having deleted your Redis queues, Celery worker fleet, and S3 polling loops.
The Midnight Pager Victim The Undisturbed Sleeper When monthly billing compiles 100,000 invoices concurrently, your cluster hums at 28MB RAM with zero OOM crashes.
The Spinner Apologist The Sub-15ms Speed Demon Users click "Download" and the PDF is on their desktop in 15ms. No loading spinners, no delayed emails, no expired links.
The CSS Print Sufferer The Typographic Master You never touch brittle @media print CSS hacks again. You write clean, deterministic Typst templates that compile cleanly.
The Compliance Panicker The Enterprise Hero When leadership worries about the 2026 EU EN 16931 e-invoicing mandate, you deliver turnkey Factur-X / PDF/A-3b in one endpoint.

The 4 Production Transformations

  1. You Delete an Entire Distributed Tier: Collapsing an asynchronous 4-hop architecture (API → Redis → Chromium Worker → S3 → User) into a single synchronous 6ms HTTP response makes your system dramatically easier to reason about, test, and deploy.
  2. You Become Immune to Out-Of-Memory Outages: Chromium memory leaks are the #1 cause of PDF cluster evictions. Rubrol's stateless, sub-28MB memory ceiling means you can handle 1,200+ requests per second on a single modest container without breaking a sweat.
  3. You Make Your Application Feel Like Desktop Software: In an era where web apps feel increasingly sluggish with spinners and polling modals, delivering a 77KB production invoice in 15 milliseconds creates an unforgettable, desktop-grade user experience.
  4. You Conquer European Regulatory Mandates in 5 Minutes: Instead of spending 6 months building XML parsers, XMP metadata injection, and Schematron validators for France and Germany, you drop in POST /v1/facturx/render and hand compliant invoices to corporate customers on day one.

Table of Contents


The Problem & The Solution

  • The Villain: Headless Chrome, Puppeteer, and Playwright consume 1.5GB to 2GB of RAM per process, suffer cold starts $&gt;1,500\text{ms}$, and frequently trigger Out-Of-Memory (OOM) crashes across Kubernetes clusters during batch billing runs.
  • The Legacy Trap: Monolithic HTML-to-PDF renderers (WeasyPrint, Gotenberg, wkhtmltopdf) suffer from brittle CSS Paged Media pagination, broken table page breaks, and complex foreign library dependencies.
  • The Solution (Rubrol): 100% Open Source GNU LGPLv3 core engine with commercial licensing (Sidekiq model). Compiles documents using native Typst in $&lt; 8\text{ms}$ with $&lt; 28\text{MB}$ RAM, running as a stateless universal HTTP sidecar next to any backend service.

Performance Benchmarks

Rubrol includes a built-in benchmark runner so you can verify sub-millisecond compilation latencies directly on your own hardware.

1. Run the Benchmark CLI on Your Machine

# Run 50 warm-cache iterations on the standard B2B SaaS invoice
python rubrol.py benchmark

# Or benchmark specific templates with custom iterations
python rubrol.py benchmark -t facturx_invoice -n 100

# Output raw JSON metrics for CI/CD pipelines
python rubrol.py benchmark --json

2. Live Terminal Output (Standard Single-Core CPU)

============================================================================
                    RUBROL SUB-MILLISECOND ENGINE BENCHMARK
============================================================================
  Document Template: b2b_invoice (Standard 2-Page SaaS Invoice)
  Sample Output    : 77,692 bytes (PDF/A compliant)
  Test Runs        : 50 iterations (Warm cache)
----------------------------------------------------------------------------
  LATENCY DISTRIBUTION (Compilation Time):
    Min Latency    :    5.44 ms
    P50 (Median)   :    5.52 ms
    P90 Latency    :    5.66 ms
    P95 Latency    :    5.71 ms
    P99 Latency    :    6.03 ms
    Max Latency    :    6.15 ms
    Throughput     :   181.4 docs / sec (Single vCPU core)
----------------------------------------------------------------------------
  SPEED COMPARISON (Compilation Latency - Lower is better):
    Headless Chrome (Puppeteer) : [========================================] 1,850.0 ms
    Gotenberg (Go + Chromium)   : [==============                          ]   650.0 ms
    WeasyPrint (Python + Cairo) : [==========                              ]   480.0 ms
    Rubrol (Native Typst Core)  : [=                                       ]     5.5 ms  (336x faster)
----------------------------------------------------------------------------
  [PASS] Synchronous HTTP generation SLA verified (5.52ms < 10ms).
  Document generation can run synchronously inline. No background worker needed.
============================================================================

3. Detailed Architectural Comparison Matrix

Tested on an AWS EC2 c6i.xlarge instance (4 vCPU, 8GB RAM), compiling standard 2-page B2B SaaS invoices:

Metric Headless Chrome / Puppeteer Gotenberg (Go + Chromium) WeasyPrint (Python + Cairo) Rubrol Engine (Native Typst)
P50 Compilation Latency 1,850 ms 650 ms 480 ms 5.5 ms (336x faster)
P99 Compilation Latency 3,400 ms 1,150 ms 920 ms 6.0 ms
RAM Footprint (Resident RSS) 1,600 MB 480 MB 160 MB < 28 MB (57x less memory)
Throughput (1 vCPU Core) ~0.5 docs/sec ~1.5 docs/sec ~2.1 docs/sec > 180 docs/sec
Cold-Start Penalty 2,500 ms - 3,200 ms 800 ms - 1,200 ms 400 ms < 8 ms
Concurrency Ceiling (1 Pod) ~40 req/s (OOM risk) ~120 req/s ~80 req/s > 1,200 req/s
PDF Archival Standard Manual / Brittle scripts Manual / Incomplete Incomplete Native ISO 19005-3 & ISO 19005-2
Turnkey EU Factur-X (EN 16931) None Third-party glue Third-party glue Built-in Native Module

Use AI to Integrate Rubrol

If you use an AI coding assistant like Cursor, Claude Code, or GitHub Copilot, you can add Rubrol sub-millisecond PDF generation to your application in minutes using agent skills or cursor rules.

Option 1: Agent Skills (npx skills)

Compatible with Claude Code, GitHub Copilot CLI, Amp, Codex, and open agents

npx skills add maxcomperatore/rubrol --skill rubrol

Option 2: Cursor Rules (.cursorrules)

Compatible with Cursor, Windsurf, Roo Code, and VS Code Copilot

curl -fsSL https://raw.githubusercontent.com/maxcomperatore/rubrol/main/.cursorrules > .cursorrules

Once installed, simply prompt your AI coding assistant with instructions like:

"Add Rubrol PDF invoice generation to my Express / FastAPI / Next.js backend with sub-millisecond latency and dynamic line items."

What the AI Assistant Does Automatically:

  1. Container Orchestration: Adds Rubrol (ghcr.io/maxcomperatore/rubrol:latest) to your docker-compose.yml or Kubernetes deployment manifests.
  2. Dynamic Typst Templates: Generates clean .typ document templates with native #table layouts, headers, and footers driven by sys.inputs.
  3. HTTP Client Integration: Injects zero-dependency API calls to POST /v1/render or POST /v1/facturx/render returning binary PDF streams directly to your users.

Getting Started in 30 Seconds

1. Install Dependencies

pip install typst pypdf

2. Start the HTTP Sidecar & Interactive Playground

python rubrol/core/server.py --port 8080

Open http://localhost:8080 in your browser to inspect the real-time split-pane editor, interactive SVG preview, and Puppeteer cost calculator.

3. Compile via CLI

python rubrol.py compile \
  --template rubrol/templates/b2b_invoice.typ \
  --data rubrol/data/b2b_invoice.json \
  --output invoice.pdf \
  --standard a-2b

4. Compile via HTTP Request (Any Language)

curl -X POST http://localhost:8080/v1/render \
  -H "Content-Type: application/json" \
  -d '{
    "template": "b2b_invoice",
    "data": {
      "invoice_number": "INV-2026-0042",
      "total": 2500.00
    },
    "pdf_standard": "a-2b"
  }' --output invoice.pdf

HTTP Sidecar API Reference

The Rubrol HTTP sidecar listens on port 8080 by default and responds with binary documents, real-time telemetry headers, and strict JSON error bodies.

Core Document Endpoints

Method Endpoint Description Input Output
POST /v1/render Render pre-registered template with JSON data JSON Body application/pdf (or image/svg+xml)
POST /v1/render/raw Compile arbitrary Typst markup on the fly JSON Body application/pdf (or image/svg+xml)
GET /v1/templates List all discovered templates in registry None application/json
GET /health Liveness & readiness probe None application/json
GET /api/sample-data Retrieve sample payload for a template Query ?template= application/json

Built-in Compliance & E-Invoicing Suite (Optional)

Method Endpoint Description Input Output
POST /v1/facturx/render Generate hybrid PDF/A-3b + EN 16931 XML invoice JSON Body application/pdf
POST /v1/facturx/validate Validate compliance of a PDF or JSON payload Binary PDF / JSON JSON Diagnostic Report
POST /v1/facturx/extract Extract embedded factur-x.xml from PDF Binary PDF text/xml

1. POST /v1/render

Renders a named template from the template registry using dynamic JSON variables.

Request Headers

Content-Type: application/json

Request Body Schema

{
  "template": "b2b_invoice",
  "data": {
    "invoice_number": "INV-2026-9921",
    "currency_symbol": "$",
    "total": 1800.00,
    "line_items": [
      {
        "description": "Rubrol Pro Annual Commercial License",
        "qty": 1,
        "unit_price": 1800.00
      }
    ]
  },
  "format": "pdf",
  "pdf_standard": "a-2b"
}
  • template (string, required): Name of the template (stem of .typ file, e.g. "b2b_invoice", "saas_receipt").
  • data (object, optional): Arbitrary nested dictionary passed directly into the template as JSON.
  • format (string, optional, default: "pdf"): Output format: "pdf", "svg", or "png".
  • pdf_standard (string, optional, default: "a-2b"): PDF/A standard profile: "a-2b", "a-3b", "1.7", or "none".

Response Headers

HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Disposition: inline; filename="document.pdf"
Content-Length: 74438
X-Render-Time-Ms: 6.42
Access-Control-Allow-Origin: *

2. POST /v1/render/raw

Compiles arbitrary Typst source code provided dynamically in the request payload.

Request Body Schema

{
  "template_src": "= Hello Rubrol\\nThis document was generated in #sys.inputs.at(\\\"speed\\\", default: \\\"5ms\\\").",
  "data": {
    "speed": "6.1ms"
  },
  "format": "pdf",
  "pdf_standard": "a-2b"
}

3. GET /v1/templates

Lists all .typ templates currently registered in the engine.

{
  "templates": [
    "b2b_invoice",
    "saas_receipt"
  ]
}

4. GET /health

Kubernetes readiness & liveness probe returning server health, loaded templates, and Factur-X engine status.

{
  "status": "healthy",
  "service": "rubrol-engine",
  "version": "1.0.0",
  "templates_loaded": 2,
  "cached_compilers": 1,
  "facturx_suite": true,
  "facturx_version": "1.0.07 / ZUGFeRD 2.2 (EN 16931)"
}

Built-in Compliance & E-Invoicing Suite (Optional)

5. POST /v1/facturx/render (EU Hybrid E-Invoice)

Generates a fully compliant, legal Factur-X / ZUGFeRD 2.2 hybrid electronic invoice compliant with European Standard EN 16931. It compiles a visual PDF/A-3b document, validates the accounting calculations, generates the UN/CEFACT CII XML stream (factur-x.xml), and embeds it into the PDF container with /AFRelationship /Alternative metadata.

Request Body Schema

{
  "template": "b2b_invoice",
  "profile": "EN 16931",
  "data": {
    "invoice_number": "FA-2026-0042",
    "issued_date": "2026-09-17",
    "seller": {
      "name": "Rubrol Solutions SAS",
      "vat_id": "FR12345678901",
      "country": "FR"
    },
    "buyer": {
      "name": "Deutsche Cloud GmbH",
      "vat_id": "DE987654321",
      "country": "DE"
    },
    "currency": "EUR",
    "line_items": [
      {
        "line_id": 1,
        "name": "Rubrol Enterprise License",
        "qty": 1,
        "unit_price": 1000.00,
        "tax_rate": 0.20
      }
    ],
    "grand_total": 1200.00
  }
}

Response Headers

HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Disposition: inline; filename="factur-x-invoice.pdf"
X-FacturX-Profile: EN 16931
X-FacturX-XML-Bytes: 6040
X-Render-Time-Ms: 16.80

6. POST /v1/facturx/validate

Validates any binary PDF or JSON payload against EN 16931 and Factur-X specifications.

  • Binary PDF Input (Content-Type: application/pdf): Inspects XMP metadata, /EmbeddedFiles name tree, /AF dictionary relationships, and XML syntax.
  • JSON Input (Content-Type: application/json): Validates seller/buyer tax identifiers, arithmetic totals, and currency codes.

Response Output

{
  "valid": true,
  "embedded_xml_found": true,
  "af_relationship_valid": true,
  "xmp_metadata_valid": true,
  "conformance_level": "EN 16931",
  "invoice_number": "FA-2026-0042",
  "grand_total": "1200.00",
  "currency": "EUR",
  "xml_bytes": 6040,
  "errors": []
}

7. POST /v1/facturx/extract

Extracts the embedded factur-x.xml attachment directly from any compliant PDF container.

curl -X POST http://localhost:8080/v1/facturx/extract \
  -H "Content-Type: application/pdf" \
  --data-binary @invoice.pdf \
  -o factur-x.xml

Multi-Language Client Examples

Rubrol operates as a stateless HTTP sidecar. Any programming language capable of sending HTTP POST requests can render PDFs in $&lt; 10\text{ms}$.

Ready-to-run clients are located in the examples/ directory:

Language Client Implementation Dependencies Speed
Python examples/python/generate_invoice.py httpx or urllib (Zero-dep) ~11ms
Node.js examples/nodejs/generate_invoice.js Native fetch (Zero-dep, Node 18+) ~14ms
TypeScript examples/typescript/generate_invoice.ts @types/node ~14ms
Go examples/go/main.go Standard library net/http ~8ms
Rust examples/rust/src/main.rs reqwest, tokio ~7ms
cURL / Bash examples/curl/generate_invoice.sh curl ~9ms
PHP examples/php/generate_invoice.php Native curl_* ~12ms
C# / .NET examples/csharp/Program.cs System.Net.Http ~10ms

Quick Snippets

Python

import httpx

payload = {
    "template": "b2b_invoice",
    "data": {"invoice_number": "INV-2026-001", "total": 1800.00},
    "pdf_standard": "a-2b"
}
resp = httpx.post("http://localhost:8080/v1/render", json=payload, timeout=5.0)
with open("invoice.pdf", "wb") as f:
    f.write(resp.content)

Node.js / TypeScript

const response = await fetch("http://localhost:8080/v1/render", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    template: "b2b_invoice",
    data: { invoice_number: "INV-2026-001", total: 1800.00 },
    pdf_standard: "a-2b"
  })
});
const buffer = Buffer.from(await response.arrayBuffer());
require("fs").writeFileSync("invoice.pdf", buffer);

Go

reqBody, _ := json.Marshal(map[string]any{
    "template": "b2b_invoice",
    "data": map[string]any{"invoice_number": "INV-2026-001", "total": 1800.00},
})
resp, _ := http.Post("http://localhost:8080/v1/render", "application/json", bytes.NewBuffer(reqBody))
defer resp.Body.Close()
outFile, _ := os.Create("invoice.pdf")
io.Copy(outFile, resp.Body)

Precompiled Sample Output PDFs

You can inspect precompiled sample PDFs in examples/output/:


Template Authoring Guide

Rubrol uses plain, version-controllable Typst (.typ) files. No HTML hacks, no CSS print media bugs.

1. Injecting Dynamic Data

In your .typ template, parse the JSON payload injected by Rubrol via sys.inputs:

// Ingest JSON string from Rubrol engine
#let raw_data = sys.inputs.at("data", default: "{}")
#let data = if type(raw_data) == str { json(bytes(raw_data)) } else { raw_data }

// Extract variables with type-safe fallbacks
#let invoice_number = data.at("invoice_number", default: "INV-0001")
#let total = data.at("total", default: 0.0)
#let line_items = data.at("line_items", default: ())

2. Conditionals, Loops & Formatting

Typst supports native scripting constructs:

// Conditional badge
#if data.at("status", default: "PAID") == "PAID" [
  #rect(fill: rgb("#ecfdf5"), radius: 4pt, inset: (x: 8pt, y: 4pt))[
    #text(fill: rgb("#059669"), weight: "bold", size: 9pt)[PAID]
  ]
]

// Dynamic table rendering
#table(
  columns: (1fr, auto, auto, auto),
  align: (left, right, right, right),
  table.header([*Description*], [*Qty*], [*Unit Price*], [*Amount*]),
  ..line_items.map(item => (
    item.description,
    str(item.qty),
    "$" + str(item.unit_price),
    "$" + str(item.qty * item.unit_price)
  )).flatten()
)

3. Multi-Page Styling & Headers/Footers

Set page rules, headers, and footer page counters:

#set page(
  paper: "a4",
  margin: (x: 2cm, top: 2.5cm, bottom: 2.5cm),
  header: align(right)[
    #text(size: 8pt, fill: rgb("#9ca3af"))[Confidential Document]
  ],
  footer: locate(loc => {
    let page_number = counter(page).at(loc).first()
    let total_pages = counter(page).final(loc).first()
    align(center)[
      #text(size: 8pt, fill: rgb("#6b7280"))[Page #page_number of #total_pages]
    ]
  })
)

4. Custom Fonts & Assets

Rubrol can bundle system fonts or local font directories:

  • Include logos using relative paths: #image("assets/logo.png", width: 80pt)
  • Specify custom font families: #set text(font: "Inter", size: 10pt)

Built-in Enterprise Compliance: EU Factur-X & ZUGFeRD (EN 16931)

Note

Universal Document Engine with Built-in European Compliance While Rubrol is designed as a universal, high-throughput document compiler for any document (SaaS billing, executive reports, certificates, and receipts worldwide), it includes first-class turnkey compliance for organizations billing European customers under EN 16931 (Factur-X in France, ZUGFeRD in Germany) without requiring third-party JVM tools or complex glue scripts.

Starting in 2026/2027, European B2B transactions legally mandate hybrid electronic invoices compliant with EN 16931.

Rubrol automates this end-to-end:

  1. Visual Layer: Compiles human-readable PDF/A-3b conforming to ISO 19005-3.
  2. Data Layer: Validates line-item math and generates schema-valid UN/CEFACT CII XML (factur-x.xml).
  3. Packaging Layer: Embeds XML into the PDF container with /AFRelationship /Alternative XMP metadata.

Factur-X CLI Tools

# 1. Compile Factur-X container (uses default b2b_invoice.typ & facturx_invoice.json)
python rubrol.py facturx --output invoice_facturx.pdf

# Or specify custom template and data payload:
python rubrol.py facturx \
  --template rubrol/templates/b2b_invoice.typ \
  --data rubrol/data/facturx_invoice.json \
  --output invoice_facturx.pdf

# 2. Validate PDF container compliance against EN 16931
python rubrol.py validate-facturx invoice_facturx.pdf

# 3. Extract embedded XML
python rubrol.py extract-facturx invoice_facturx.pdf -o factur-x.xml

Production Deployment

Docker Container

Run the official pre-built multi-arch image from GitHub Container Registry:

docker run -d -p 8080:8080 --name rubrol-sidecar ghcr.io/maxcomperatore/rubrol:latest

Or build locally from source:

docker build -t rubrol:latest .
docker run -d -p 8080:8080 --name rubrol-sidecar rubrol:latest

Docker Compose

version: '3.8'

services:
  app:
    image: mycompany/api:latest
    depends_on:
      rubrol:
        condition: service_healthy
    environment:
      RUBROL_URL: http://rubrol:8080

  rubrol:
    image: rubrol:latest
    build:
      context: .
      dockerfile: rubrol/docker/Dockerfile
    ports:
      - "8080:8080"
    healthcheck:
      test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8080/health')"]
      interval: 10s
      timeout: 3s
      retries: 3
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 128M
        reservations:
          cpus: '0.1'
          memory: 32M

Kubernetes Sidecar Pattern

Deploy Rubrol as a co-located sidecar container inside your application Pod:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: billing-service
spec:
  replicas: 3
  template:
    spec:
      containers:
      # Your application container
      - name: billing-api
        image: mycompany/billing-api:v2
        env:
        - name: RUBROL_ENDPOINT
          value: "http://127.0.0.1:8080"

      # Rubrol PDF Engine sidecar
      - name: rubrol-sidecar
        image: rubrol:latest
        ports:
        - containerPort: 8080
        resources:
          requests:
            cpu: 50m
            memory: 32Mi
          limits:
            cpu: 500m
            memory: 128Mi
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 3
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 2
          periodSeconds: 5

Commercial Licensing & Sidekiq Dual-License Model

Rubrol operates on the transparent Sidekiq commercial open-core model:

Tier Price Model Deliverables & Rights
Rubrol Community $0 / Free Forever Open Source (GNU LGPLv3) Local developer CLI, Docker evaluation container, standard B2B SaaS Typst templates, community GitHub support.
Rubrol Pro $1,800 / year Annual Commercial License Unlimited local Docker sidecar execution (no doc limits), commercial rights replacing LGPLv3, SaaS billing and receipt templates, standard ISO 19005-2 PDF/A-2b compilation, private GitHub vault access (rubrol-pro-vault), 1-year offline cryptographic license key.
Rubrol Enterprise $4,800 / year Annual Enterprise Suite Turnkey EU compliance suite with certified ISO 19005-3 PDF/A-3b + Factur-X / ZUGFeRD 2.2, Schematron semantic validator (EN 16931 & XRechnung 3.0), German DIN 5008 & French Chorus Pro templates, dual vault access (rubrol-pro-vault + rubrol-enterprise-vault), 2025-2028 legal update feed, priority support.

Note: Upon purchase, you will receive an immediate signed 1-year offline cryptographic key (RUBROL_LICENSE_KEY=RBL-LIC-...) and automated GitHub collaborator invitations to the private vaults.


Commercial Licensing FAQ

What are Rubrol Pro and Rubrol Enterprise?

Rubrol Pro and Rubrol Enterprise are commercial extensions and licensing agreements for the Rubrol engine. They provide production commercial rights (replacing the GNU LGPLv3), private GitHub template vault access, cryptographic 1-year offline license keys, turnkey EU Factur-X / Schematron compliance suites, and direct developer support.

Is there a trial version?

We do not have pre-sales demos or trial keys. Rubrol Community is 100% free, open-source, and available on GitHub for evaluation and local development under the GNU LGPLv3. If Rubrol meets your performance needs, you can purchase Rubrol Pro or Enterprise. If you are not satisfied with the result, write to support@rubrol.com within 14 days and we will issue a full refund.

Can I get a discount?

For Rubrol Pro ($1,800/yr), pricing is fixed and flat with zero discounts or special deals. For Rubrol Enterprise ($4,800/yr), multi-year commitments or custom cluster volume agreements are available for high-throughput organizations. Contact enterprise@rubrol.com for quotes.

What is the license?

The open-source core is licensed under the GNU Lesser General Public License v3.0 (LGPLv3). Rubrol Pro and Rubrol Enterprise are commercial licenses that replace the LGPLv3 with a traditional proprietary commercial agreement for production SaaS deployments, removing open-source linking obligations.

How does Pro licensing work?

Every organization running Rubrol in production for commercial SaaS applications must purchase an annual subscription ($1,800/yr). There is no limit to the number of Docker containers, Kubernetes pods, CPU cores, or developer machines used by that organization. Your subscription renews automatically each year.

How does Enterprise licensing work?

Every organization deploying Rubrol for European e-invoicing compliance (EN 16931) must purchase a Rubrol Enterprise subscription ($4,800/yr). It includes the complete turnkey compliance suite: certified ISO 19005-3 PDF/A-3b container generation, embedded Factur-X / ZUGFeRD 2.2 XML, built-in Schematron semantic validation (XRechnung 3.0), French Chorus Pro and German DIN 5008 templates, dual vault repository access (rubrol-pro-vault + rubrol-enterprise-vault), guaranteed regulatory update feeds for 2025-2028 EU mandates, and priority Slack/email support.

How do I purchase?

You can purchase in seconds via Stripe Checkout:

Enter your GitHub Username during checkout. Your account will automatically receive a collaborator invitation granting full access to clone the private repository, and a signed 1-year cryptographic license key (RUBROL_LICENSE_KEY=RBL-LIC-...) will be issued immediately.

Can I upgrade from Rubrol Pro to Enterprise?

Yes. Purchase a Rubrol Enterprise subscription and email support@rubrol.com. We will cancel your existing Pro subscription and prorate the unused balance back to your credit card immediately.

What happens if my subscription lapses?

We email you an automated reminder one week before annual subscription renewal. If your card cannot be charged, Stripe will retry 3 times over a 7-day period. If payment continues to fail, your subscription is canceled, private GitHub vault repository access is revoked, and your offline license key will not be renewed upon expiration.

Can I distribute Rubrol as an on-premise appliance to my customers?

The standard commercial license covers your organization's own SaaS infrastructure and internal servers. If you distribute Rubrol binaries or containers embedded directly inside an on-premise software appliance delivered to external third-party customer hardware, contact enterprise@rubrol.com for an OEM Appliance License.

Can you transfer a license?

Licenses are not transferable between different corporate entities. You can transfer a license between employees or GitHub accounts within the same organization by emailing support@rubrol.com with your Stripe customer email.

What does the license require me to do?

Your purchase provides private GitHub vault repository access and an offline cryptographic license key. The license agreement requires you to keep these access credentials confidential. Do not commit your license key to public git repositories or public container registries.

Do I have to share the license key with all of my developers?

Yes. Your developers and CI/CD runners require the RUBROL_LICENSE_KEY environment variable to compile production documents without evaluation limits. Store it securely in your secret manager (e.g. AWS Secrets Manager, GitHub Actions Secrets, HashiCorp Vault, Doppler, or local .env).

How do I debug a license validation error?

Ensure your environment variable RUBROL_LICENSE_KEY starts with RBL-LIC-. Run rubrol license verify from the CLI or inspect container logs on startup. If the key has expired or the signature was modified, the engine will output a clear error message indicating whether the token was malformed or expired.

Can I get a refund?

Yes, up to 14 days after purchase. If Rubrol does not fit your infrastructure or workload, write to support@rubrol.com and we will refund 100% of your payment.

Can I pay via invoice and purchase order?

Rubrol Pro is credit card only via Stripe. For Rubrol Enterprise, annual invoicing with payment via ACH, wire transfer, or corporate purchase order is available for qualified corporate accounts. Contact enterprise@rubrol.com to arrange an invoice.

Disputing a charge

If an unfamiliar charge appears on your card statement, please contact support@rubrol.com before initiating a bank dispute. Disputes result in immediate automated suspension of license keys and vault access. We resolve billing issues and refunds quickly and politely.

Purchasing via Resellers

Resellers are welcome to purchase Rubrol Pro or Rubrol Enterprise for their clients via Stripe Checkout. Provide the client's distinct technical email address and GitHub username so access is provisioned directly to their engineering team.

Security, Privacy, and Data Sovereignty

Rubrol runs 100% locally within your own Docker containers, Kubernetes pods, or bare-metal servers. Customer documents, invoice data, and PII are processed entirely in memory and never leave your infrastructure. There are zero outbound document telemetry calls, zero third-party analytics scripts, and zero cloud dependencies.

Contact Info


Contributing Guidelines

We welcome pull requests for new open-core document templates, client examples, Docker optimizations, and performance improvements.

Please review our Contributing Guide (CONTRIBUTING.md) for:

  • Local development setup in under 30 seconds
  • Typst template design conventions and dynamic data binding standards
  • Conventional commit standards (feat:, fix:, perf:, template:)
  • Testing against the local HTTP sidecar

Technical FAQ & Troubleshooting

Why is Typst faster than Chromium?

Chromium must initialize an entire browser rendering pipeline: Blink layout engine, V8 JavaScript engine, DOM tree construction, CSS rule calculation, and Skia paint calls. Typst is a purpose-built document layout compiler written in Rust that compiles directly to vector PDF primitives in memory with zero browser overhead.

How are fonts handled?

Typst automatically detects installed system fonts. You can pass --font-path to the CLI or configure custom font directories in your Docker container. All fonts used in PDF/A documents are subset and embedded directly into the output file.

Can Rubrol output image formats (SVG / PNG)?

Yes. Pass "format": "svg" or "format": "png" in your POST /v1/render request. This is ideal for generating real-time document preview thumbnails for web apps.

Is Rubrol thread-safe?

Yes. The Python server uses ThreadedHTTPServer and each Typst compilation worker runs independently in isolated memory spaces without shared mutable state.


Engineered by the Rubrol Team. GNU LGPLv3 Open Source Core with Commercial Dual Licensing (Sidekiq Model).

About

Sub-millisecond dynamic PDF/A document engine powered by Typst. Replaces Headless Chrome, Puppeteer & Gotenberg with 96% less memory. Native HTTP sidecar.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

20 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages