Home
Softono

Easypdf Lite

Open source MIT TypeScript
14
Stars
1
Forks
0
Issues
1
Watchers
3 months
Last Commit

 About Easypdf Lite

Lightweight self-hostable invoice PDF generator. Bun + jsPDF, 3 deps.

Platforms

Web Self-hosted

Languages

TypeScript

Need Help Installing Easypdf Lite?

We provide expert installation service for this software. Our team will install, configure, and secure Easypdf Lite on your server. plans start at just $30.

Easypdf Lite

View on GitHub

EasyPDF Lite

A lightweight, self-hostable invoice PDF generator. No cloud, no accounts.

Try it: h1d.github.io/easypdf-lite

EasyPDF Lite

Why

Existing open-source invoice generators are surprisingly heavy to self-host — 1 GB+ Docker images, dozens of environment variables, external databases. This one is a 10 MB container. One command, no config, no database.

Inspired by easy-invoice-pdf.

What you get

  • Invoice form with live PDF preview and one-click download
  • 11 languages, 67 currencies, VAT/tax calculations
  • Shareable invoice links (URL-encoded, compressed)
  • Payment QR codes generated from a shareable payment URL
  • Saved seller/buyer profiles (localStorage)
  • Cyrillic/Unicode support (embedded Open Sans fonts)
  • 64 e2e tests
URL API — generate invoice links programmatically

The app accepts a ?data= URL parameter containing a compressed invoice. You can generate these links from any language to create pre-filled invoices — useful for billing systems, CRMs, or automated workflows.

How it works: JSON → key compression → lz-string → URL

import LZString from "lz-string";

// Fetch the key compression map — always in sync with the app.
const KEY_MAP = await fetch("https://h1d.github.io/easypdf-lite/key-map.json")
  .then((r) => r.json());

function compressKeys(obj) {
  if (Array.isArray(obj)) return obj.map(compressKeys);
  if (obj && typeof obj === "object") {
    return Object.fromEntries(
      Object.entries(obj).map(([k, v]) => [KEY_MAP[k] ?? k, compressKeys(v)])
    );
  }
  return obj;
}

const invoice = {
  language: "en",
  currency: "USD",
  dateOfIssue: "2026-01-15",
  dateOfService: "2026-01-15",
  paymentDue: "2026-02-15",
  seller: { name: "Acme Corp", address: "123 Main St" },
  buyer:  { name: "Client Inc", address: "456 Oak Ave" },
  items: [
    { name: "Consulting", amount: 10, unit: "hours",
      netPrice: 150, vat: 0, netAmount: 1500, vatAmount: 0, preTaxAmount: 1500 },
  ],
  total: 1500,
};

const compressed = LZString.compressToEncodedURIComponent(
  JSON.stringify(compressKeys(invoice))
);
const url = `https://h1d.github.io/easypdf-lite/?data=${compressed}`;

Only include the fields you need — the app fills in defaults for everything else. The key map is served at /key-map.json and stays in sync with the source automatically. See src/types.ts for the full InvoiceData shape.

What you don't get

API endpoints, analytics, Sentry, newsletters, about pages, or hundreds of MB of node_modules.

Compared to easy-invoice-pdf

Original Lite
Runtime Node.js + Next.js Bun (build) + nginx (serve)
UI React 19 + shadcn/ui Vanilla TS
Styling Tailwind CSS Plain CSS
PDF @react-pdf/renderer jsPDF (browser-side)
Dependencies 50+ 4 runtime, 5 dev
Client payload ~2 MB ~940 KB
Memory (idle) 290 MB 4 MB
Docker image 6.4 GB 10 MB
node_modules 1.3 GB 85 MB

Self-hosting

docker run -d -p 3000:3000 ghcr.io/h1d/easypdf-lite:latest

Open http://localhost:3000.

Development

bun install
bun run dev        # http://localhost:3000

bun run build      # bundle for production
bun run start      # serve production build

# tests
bunx playwright install --with-deps chromium
bun run test

License

MIT