A typesafe, edge-native, framework-agnostic PDF library for React. Real Tailwind. Real typography. No Chromium.
import { pdf, Document, Page } from '@imprint-pdf/react';
const response = await pdf(
<Document>
<Page size="A4" className="p-12 font-sans bg-white">
<h1 className="text-3xl font-bold tracking-tight">Hello, PDF</h1>
<p className="mt-4 text-base leading-relaxed text-pretty">
Real Tailwind. Real React. Real typography. No browser.
</p>
</Page>
</Document>,
);That's it. pdf() returns a Response you can hand to any web framework. Pass
{ as: 'bytes' } for a Uint8Array, { as: 'stream' } for a ReadableStream.
Everything else is config the library doesn't make you write.
Generating a PDF in a JavaScript app shouldn't require launching a 200 MB
browser. It shouldn't require learning a hand-rolled StyleSheet DSL. It
shouldn't require pushing coordinates by hand. And it should run in the same
runtime as the rest of your code — Node, Bun, Vercel Edge, Cloudflare Workers,
the browser.
imprint-pdf gives you the actual Tailwind v4 Oxide compiler, the actual HarfBuzz shaping engine, the actual Knuth–Plass justification algorithm, and the actual Taffy layout engine (Block + Flexbox + CSS Grid). All Apache-2.0. All in one install.
- Real Tailwind classes.
p-4 grid grid-cols-12 gap-6 text-pretty— the real compiler, not a translator, not a subset. Plugins, arbitrary values, OKLCH colors, and@themedesign tokens all work. Supports Tailwind v3 and v4 — auto-detected from your project's installed version. - Real React. A custom reconciler. JSX components, refs, hooks. HTML
elements (
<div>,<h1>,<table>) compile to semantically tagged PDF nodes. Works on React 18 and 19 — both reconciler majors are bundled. - Real typography. HarfBuzz shaping (Arabic, Indic, Thai, CJK, kerning, ligatures, variable fonts), Knuth–Plass justification, Plass page breaking (widows / orphans / footnotes).
- One API.
pdf(<Doc />)returns aResponse.pdf(<Doc />, { as: 'bytes' })returns aUint8Array.pdf(<Doc />, { as: 'stream' })returns aReadableStream. Same function everywhere — Node, Bun, the browser, edge. - Edge-native. Sub-100 ms cold on Cloudflare Workers and Vercel Edge.
- CSS Grid. Taffy (Rust → WASM). Block + Flexbox + Grid in one layout pass.
- Vector charts. Recharts, Visx, ECharts, Observable Plot SVG output flows through the vector pipeline — crisp at any zoom, no rasterized PNG.
- AcroForms in JSX.
<TextField>,<Checkbox>,<RadioGroup>,<Signature>declared as components. Real PDF form fields, not screenshots. - Print-grade output. PDF/X-4 + CMYK + ICC profiles + PDF/UA-1 tagged PDF + PKCS#7 signing + factur-X / ZUGFeRD, all as opt-in add-ons.
Full documentation lives in docs/. For LLMs / AI agents, see
llms.txt (index) and llms-full.txt (single-file
context).
- Overview — what imprint-pdf does and where it fits
- Quick start — render your first PDF in five minutes
- Philosophy — why no Chromium, why real Tailwind
- Concepts — documents, pages, layout, the writer
- Guides — components, Tailwind, fonts, charts, forms, accessibility
- Frameworks — Next.js, Vite, Bun, Cloudflare
- Cookbook — invoices, contracts, reports
- Reference — every component, every CLI flag
pnpm add @imprint-pdf/react @imprint-pdf/core tailwindcss
pnpm add -D @imprint-pdf/cli
npx imprint initimprint init detects your framework (Next.js, Vite, generic Node), wires the
right plugin into your config, scaffolds an example template + route, and prints
the first command to run.
// Next.js / Hono / Bun route — returns a Response with PDF headers
import { pdf } from '@imprint-pdf/next';
export const GET = () => pdf(<Invoice data={data} />);// Cloudflare Worker — same `pdf()`, edge-friendly build
import { pdf } from '@imprint-pdf/react/standalone';
import wasm from '@imprint-pdf/react/imprint.wasm';
export default {
fetch: () => pdf(<Invoice data={…} />, { wasm }),
};// Writing to disk — `{ as: 'bytes' }` gives back a Uint8Array
import { pdf } from '@imprint-pdf/react';
import { writeFileSync } from 'node:fs';
const bytes = await pdf(<Invoice data={data} />, { as: 'bytes' });
writeFileSync('./invoice.pdf', bytes);Source code → React reconciler → PdfNode IR
│
▼
Tailwind resolver
(Oxide v4 or PostCSS v3)
│
▼
Layout pass (Taffy WASM)
+ inline layout (Parley-lite)
+ Knuth–Plass paragraph breaker
+ Plass page breaker
│
▼
Text & vector pipeline
(HarfBuzz, ICU4X, fontkit, resvg)
│
▼
PDF writer (pdf-lib v0 → imprint-pdf v1)
│
▼
Response | Uint8Array | ReadableStream
For the full design, see ARCHITECTURE.md.
| Capability | @react-pdf |
Satori | pdfme | Forme | Chromium SaaS | Typst | imprint-pdf |
|---|---|---|---|---|---|---|---|
| Real Tailwind classes | ❌ (DSL) | subset | ❌ | ✅ | ✅ | ❌ | ✅ |
| React / JSX components | ✅ | ✅ | part. | ✅ | ❌ | ❌ | ✅ |
| Edge runtimes (CF Workers) | part. | ✅ | part. | ✅ | ❌ | ✅ | ✅ |
| CSS Grid | ❌ | ❌ | ❌ | ❓ | ✅ | ✅ | ✅ (Taffy) |
| HarfBuzz-grade shaping | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ |
| Knuth–Plass justification | ❌ | ❌ | ❌ | ❌ | Prince ≈ | ✅ | ✅ |
| Variable fonts | part. | ❌ | ❌ | ❓ | ✅ | ✅ | ✅ |
| Arabic / Indic / Thai / CJK | weak | weak | weak | part. | ✅ | ✅ | ✅ |
| Vector charts | ❌ | ❌ | ❌ | ❓ | ✅ | ✅ | ✅ |
| AcroForms in JSX | ❌ | n/a | tmpl. | ✅ | ❌ | ❌ | ✅ |
| PDF/X-4 + CMYK | ❌ | ❌ | ❌ | part. | DocRaptor | part. | ✅ |
| PDF/UA-1 tagged PDF | ❌ | ❌ | ❌ | ✅ | DocRaptor | part. | ✅ |
| Sub-100 ms edge cold start | n/a | ✅ | part. | ✅ | ❌ | ✅ | ✅ |
| Same code: client + edge + server | part. | ✅ | ✅ | ✅ | n/a | ✅ | ✅ |
Measured with @imprint-pdf/bench on an Apple M-series laptop
(Node 20, 30 runs, 5 warmup), rendering the same 1-page invoice through every
JSX-driven library.
| Library | mean | p95 | p99 | Output |
|---|---|---|---|---|
@imprint-pdf/react |
4.3 ms | 5.2 ms | 5.8 ms | 6.2 KB |
@react-pdf/renderer |
13.7 ms | 15.6 ms | 16.8 ms | 3.3 KB |
| Puppeteer (warm, browser reused) | 50.6 ms | 51.1 ms | 51.1 ms | 46.9 KB |
| Puppeteer (cold, launch per render) | 473 ms | 494 ms | 494 ms | 46.9 KB |
3.15× faster than @react-pdf/renderer on the only fair head-to-head comparison
(both consume JSX, both run a layout pass). ~12× faster than warm Chromium,
~110× faster than cold Chromium — the cold number is what serverless functions
actually pay, plus a 200 MB binary download.
pnpm bench # runs competitors + complexity + pipeline + features
pnpm bench:chromium # opt-in, downloads Chromium on first run
pnpm bench:all # everything, including chromiumImperative libraries (pdfkit, pdf-lib, jsPDF) and template-based ones
(pdfme) are intentionally excluded — they're a different paradigm and the
comparison would flatter imprint-pdf on ergonomics while making it look slow on
µs-per-glyph.
examples/next-app— Next.js App Router + RSC + edge routeexamples/vite-react— Vite + React SPA downloadexamples/cloudflare-worker— Worker that streams a PDF in <100 ms coldexamples/bun-server— Bun + Hono PDF endpointexamples/react18-tailwind3-nextjs— Next 14 + React 18 + Tailwind 3 smoke
pnpm --filter @imprint-pdf/example-next-app dev1.0.0-alpha. Architecture is settled (ARCHITECTURE.md);
the API is close. Pin exact versions.
| Phase | Versions | What it means |
|---|---|---|
| Alpha | 1.0.0-alpha.x |
Anything can change in any release. |
| Beta | 1.0.0-beta.x |
Public API frozen modulo bugs. Soak before GA. |
| 1.0 | 1.0.0 |
First stable release. Semver from here on. |
| Post-1.0 | 1.x.y+ |
Backwards-compatible features and fixes. |
See STABILITY.md for the full contract.
imprint-pdf is Apache-2.0 and self-funded. If your company ships PDFs through it
— or you'd like to — sponsorship is what unlocks the next milestones on the
roadmap, including the v1.x custom PDF writer that drops the
pdf-lib runtime dependency for a smaller bundle and edge-friendlier output.
GitHub Sponsors → @tamimbinhakim
Backers and sponsors will be credited in releases and the repo README.
Apache-2.0 — every package. Engine, React layer, Tailwind compiler, CLI,
integrations, and the compliance & print add-ons (PDF/X-4 + CMYK + ICC,
PDF/UA-1 tagged PDF, PKCS#7 signing, factur-X / ZUGFeRD). No commercial seats,
no time-bombed source. See LICENSING.md.
pnpm install
pnpm dev # turbo run dev across all packages
pnpm test # vitest across the monorepo
pnpm typecheck # composite tsc
pnpm lint # biome checkSee CONTRIBUTING.md and
.github/RELEASING.md.
© Tamim Bin Hakim and contributors.