← Back to home

Framework Integration

Using pdf-gen from TypeScript

A dependency-free, fluent client built on the Fetch API — works the same in Node and in the browser.

1. Configuration

The client only needs the URL of your instance. In Node, read it from an environment variable:

# .env
PDF_GEN_API_URL=https://pdf.your-domain.dev/api/gen

In the browser, there is no process environment, so pass the URL directly (e.g. from a public build-time constant such as NEXT_PUBLIC_PDF_GEN_API_URL).

⚠️ Don't use the demo instance (https://pdf.mathieutu.dev) in production: it is not versioned and can break without notice. Fork the project and deploy your own instance (Docker or Vercel).

2. The client

This fluent client builds a POST /api/gen call from raw HTML and/or URLs (web pages, PDFs or images) to merge, using only the built-in fetch API. It runs unchanged in Node (18+), edge runtimes, and browsers.

export class PdfGenerator {
  #html?: string
  #urls: string[] = []
  #filename?: string

  constructor(private readonly apiUrl: string) {}

  html(html: string): this {
    this.#html = html

    return this
  }

  url(url: string): this {
    this.#urls.push(url)

    return this
  }

  urls(urls: Iterable<string>): this {
    for (const url of urls) this.url(url)

    return this
  }

  filename(filename: string): this {
    this.#filename = filename

    return this
  }

  async generate(): Promise<ArrayBuffer> {
    const response = await fetch(this.apiUrl, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        html: this.#html,
        urls: this.#urls,
        filename: this.#filename,
      }),
    })

    if (!response.ok) {
      throw new Error(`Failed to generate PDF: ${await response.text()}`)
    }

    return response.arrayBuffer()
  }
}

3. Usage

Node: generate and save to disk

import { writeFile } from 'node:fs/promises'
import { PdfGenerator } from './pdf-generator'

const pdf = new PdfGenerator(process.env.PDF_GEN_API_URL!)

const buffer = await pdf
  .html('<h1>Invoice #42</h1>')
  .filename('invoice-42.pdf')
  .generate()

await writeFile('invoice-42.pdf', Buffer.from(buffer))

Node: return the PDF from an API route

// e.g. a Next.js API route or an Express handler
import { PdfGenerator } from './pdf-generator'

export async function GET() {
  const buffer = await new PdfGenerator(process.env.PDF_GEN_API_URL!)
    .url('https://example.com/report')
    .generate()

  return new Response(buffer, {
    headers: {
      'Content-Type': 'application/pdf',
      'Content-Disposition': 'attachment; filename="report.pdf"',
    },
  })
}

Browser: generate and trigger a download

import { PdfGenerator } from './pdf-generator'

const pdf = new PdfGenerator('https://pdf.your-domain.dev/api/gen')

async function downloadInvoice(html: string) {
  const buffer = await pdf.html(html).filename('invoice.pdf').generate()

  const url = URL.createObjectURL(new Blob([buffer], { type: 'application/pdf' }))
  const link = Object.assign(document.createElement('a'), { href: url, download: 'invoice.pdf' })
  link.click()
  URL.revokeObjectURL(url)
}

Merge an HTML cover page with existing PDFs/URLs

const buffer = await new PdfGenerator(apiUrl)
  .html('<h1>Cover page</h1>')
  .urls(attachments.map(a => a.url))
  .generate()

Parameter reference

MethodAPI fieldDescription
html(html)htmlRaw HTML content
url(url) / urls(urls)urlsA page, PDF or image URL, merged in the order it was added
filename(name)filenameFile name attached to the generated document

For direct file uploads (PDF/image/HTML as multipart/form-data, 4 MB max), see the multipart form data section of the project's README.

Mathieu TUDISCO

Trainer and pragmatic full-stack lead developer, currently open to short freelance assignments (let's talk!). Passionate about PHP and TypeScript, regular open-source contributor.

When I'm not in front of a screen, you'll usually find me cycling around Lyon, or in the surrounding mountains, where I spend a fair amount of time underground and under waterfalls...

pdf-gen is an open-source side project, born from the need for a simple, self-hostable API to generate and merge PDFs without vendor lock-in or per-document pricing.

View contributors