Guides

How to Generate PDF from Text Programmatically: 5 Methods Compared for 2026

Subham Jobanputra Subham Jobanputra
January 11, 2026
Illustration showing five methods of generating PDFs from text, with a central PDF icon connected by arrows to client-side generation in the browser, server-side generation using Python, headless browsers, API or service-based PDF generatio

Introduction

You've built a beautiful web app. Your users love it. Then someone asks: "Can I download this as a PDF?"

Suddenly you're down a rabbit hole of broken layouts, missing fonts, and Stack Overflow posts from 2019 that no longer work.

If you've ever tried to generate PDF from text programmatically, you know the pain. What seems like a simple task—turning text or HTML into a clean PDF—often becomes days of debugging CSS, wrestling with deprecated libraries, and questioning your career choices.

This guide cuts through the noise. We'll compare five battle-tested methods to generate PDFs programmatically, with real code examples, honest trade-offs, and clear recommendations based on your specific use case.


Why Generating PDFs Programmatically Is Harder Than It Looks

Before diving into solutions, let's understand why this problem exists.

PDF (Portable Document Format) was designed for print—fixed layouts, precise positioning, exact dimensions. HTML and CSS were designed for screens—fluid layouts, responsive designs, dynamic content.

These two paradigms clash when you try to convert one to the other:

  • Layout breaks: Flexbox and CSS Grid often render incorrectly

  • Font issues: Custom fonts may not embed properly, producing "tofu" (□□□) characters

  • Dynamic content timing: JavaScript-rendered content might not load before capture

  • Page breaks: Content cuts off awkwardly between pages

  • Performance: Some methods consume enormous server resources

Understanding these challenges helps you choose the right tool for your needs.


Method 1: Client-Side JavaScript Libraries

Best for: Simple documents, receipts, labels, basic reports

Popular libraries: jsPDF, pdfmake, html2pdf.js

How It Works

Client-side libraries generate PDFs directly in the browser—no server required. They work by either drawing to a canvas or building PDF primitives from scratch.

Code Example: jsPDF

import { jsPDF } from 'jspdf';

function generatePDF(text) {
  const doc = new jsPDF();
  
  // Add text to the PDF
  doc.setFont('helvetica', 'normal');
  doc.setFontSize(12);
  doc.text(text, 20, 20);
  
  // Add a title
  doc.setFontSize(18);
  doc.setFont('helvetica', 'bold');
  doc.text('My Report', 105, 15, { align: 'center' });
  
  // Save the PDF
  [doc.save](<http://doc.save>)('document.pdf');
}

generatePDF('Hello, this is my programmatically generated PDF!');

Code Example: html2pdf.js

import html2pdf from 'html2pdf.js';

const element = document.getElementById('content');

html2pdf()
  .set({
    margin: 10,
    filename: 'report.pdf',
    image: { type: 'jpeg', quality: 0.98 },
    html2canvas: { scale: 2 },
    jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' }
  })
  .from(element)
  .save();

Pros

  • No server infrastructure required

  • Works offline

  • Free and open source

  • Fast for simple documents

Cons

  • Limited CSS support (no flexbox, poor grid support)

  • Complex layouts break

  • Bundle size impacts app performance (jsPDF: ~230KB minified)

  • Can't handle JavaScript-rendered content reliably

  • Font embedding is tricky

Verdict

✅ Use for: Simple receipts, basic text documents, quick prototypes

❌ Avoid for: Complex layouts, branded documents, production apps


Method 2: Server-Side PDF Libraries

Best for: Full control, specific formatting requirements, offline generation

Popular libraries: PDFKit (Node.js), ReportLab (Python), iTextSharp (.NET)

How It Works

Server-side libraries give you low-level control over PDF creation. You construct documents programmatically—positioning each element manually.

Code Example: PDFKit (Node.js)

const PDFDocument = require('pdfkit');
const fs = require('fs');

function generatePDF(text, outputPath) {
  const doc = new PDFDocument();
  
  doc.pipe(fs.createWriteStream(outputPath));
  
  // Add styled content
  doc
    .fontSize(24)
    .font('Helvetica-Bold')
    .text('My Report', { align: 'center' });
  
  doc.moveDown();
  
  doc
    .fontSize(12)
    .font('Helvetica')
    .text(text, {
      width: 450,
      align: 'justify'
    });
  
  // Add a table-like structure
  doc.moveDown();
  doc.text('Item          Price');
  doc.text('Widget A      $10.00');
  doc.text('Widget B      $15.00');
  
  doc.end();
}

generatePDF('This is my text content for the PDF document.', 'output.pdf');

Code Example: ReportLab (Python)

from reportlab.lib.pagesizes import letter
from reportlab.pdfgen import canvas
from reportlab.lib.units import inch

def generate_pdf(text, output_path):
    c = canvas.Canvas(output_path, pagesize=letter)
    width, height = letter
    
    # Add title
    c.setFont('Helvetica-Bold', 18)
    c.drawCentredString(width / 2, height - inch, 'My Report')
    
    # Add body text
    c.setFont('Helvetica', 12)
    text_object = c.beginText(inch, height - 2 * inch)
    
    for line in text.split('\\n'):
        text_object.textLine(line)
    
    c.drawText(text_object)
    [c.save](<http://c.save>)()

generate_pdf('This is my programmatically generated PDF content.', 'output.pdf')

Pros

  • Complete control over every element

  • No rendering inconsistencies

  • Excellent for data-driven documents (invoices, reports)

  • Lightweight and fast

Cons

  • No HTML/CSS support—you position everything manually

  • Steep learning curve

  • Significant development time for complex layouts

  • Recreating existing web designs is painful

Verdict

✅ Use for: Invoices, receipts, data reports, documents designed PDF-first

❌ Avoid for: Converting existing web UI to PDF, complex layouts


Method 3: Headless Browsers (Puppeteer/Playwright)

Best for: Pixel-perfect HTML-to-PDF, JavaScript-rendered content

Popular tools: Puppeteer, Playwright

How It Works

Headless browsers launch a real browser (Chrome/Firefox) without a visible window, render your HTML fully (including JavaScript), then "print" to PDF.

Code Example: Puppeteer

const puppeteer = require('puppeteer');

async function generatePDF(htmlContent, outputPath) {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  
  // Set content or navigate to URL
  await page.setContent(htmlContent, {
    waitUntil: 'networkidle0'
  });
  
  // Generate PDF
  await page.pdf({
    path: outputPath,
    format: 'A4',
    printBackground: true,
    margin: {
      top: '20mm',
      bottom: '20mm',
      left: '15mm',
      right: '15mm'
    }
  });
  
  await browser.close();
}

const html = `
  <html>
    <head>
      <style>
        body { font-family: Arial, sans-serif; }
        h1 { color: #333; text-align: center; }
        .content { padding: 20px; }
      </style>
    </head>
    <body>
      <h1>My Report</h1>
      <div class="content">
        <p>This HTML will be converted to a pixel-perfect PDF.</p>
      </div>
    </body>
  </html>
`;

generatePDF(html, 'output.pdf');

Code Example: Playwright

const { chromium } = require('playwright');

async function generatePDF(htmlContent, outputPath) {
  const browser = await chromium.launch();
  const page = await browser.newPage();
  
  await page.setContent(htmlContent, {
    waitUntil: 'networkidle'
  });
  
  await page.pdf({
    path: outputPath,
    format: 'A4',
    printBackground: true
  });
  
  await browser.close();
}

Pros

  • Full CSS support (flexbox, grid, everything)

  • Handles JavaScript-rendered content (React, Vue, Angular)

  • Pixel-perfect output matching browser rendering

  • Mature ecosystem

Cons

  • Heavy resource usage (200-300MB RAM per instance)

  • Slow cold starts (5-14 seconds on first launch)

  • Infrastructure complexity (Docker images ~1.9GB)

  • Scaling challenges (one browser per concurrent request)

  • Zombie processes can crash servers

Verdict

✅ Use for: Complex web layouts, SPA content, when you control infrastructure

❌ Avoid for: High-volume production, serverless environments, limited resources


Method 4: PDF Generation APIs

Best for: Production apps, teams avoiding infrastructure, scalability

Popular services: PDFRise, DocRaptor, PDFShift, API2PDF

How It Works

PDF APIs handle all the complexity—rendering engines, scaling, resource management. You send HTML/text, they return a PDF.

Code Example: PDFRise API

const fetch = require('node-fetch');
const fs = require('fs');

async function generatePDF(htmlContent) {
  const response = await fetch('<https://api.pdfrise.com/v1/pdf>', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': 'Bearer YOUR_API_KEY'
    },
    body: JSON.stringify({
      html: htmlContent,
      format: 'A4',
      margin: { top: 20, bottom: 20, left: 15, right: 15 }
    })
  });
  
  const pdfBuffer = await response.buffer();
  fs.writeFileSync('output.pdf', pdfBuffer);
}

const html = `
  <html>
    <body>
      <h1 style="text-align: center; color: #333;">My Report</h1>
      <p>This is my programmatically generated PDF via API.</p>
    </body>
  </html>
`;

generatePDF(html);

Code Example: Python

import requests

def generate_pdf(html_content, output_path):
    response = [requests.post](<http://requests.post>)(
        '<https://api.pdfrise.com/v1/pdf>',
        headers={
            'Content-Type': 'application/json',
            'Authorization': 'Bearer YOUR_API_KEY'
        },
        json={
            'html': html_content,
            'format': 'A4',
            'printBackground': True
        }
    )
    
    with open(output_path, 'wb') as f:
        f.write(response.content)

html = '''
<html>
  <body>
    <h1>Invoice #12345</h1>
    <p>Thank you for your purchase!</p>
  </body>
</html>
'''

generate_pdf(html, 'invoice.pdf')

Pros

  • Zero infrastructure to manage

  • Consistent, pixel-perfect rendering

  • Handles scaling automatically

  • Fast integration (30 minutes vs. weeks)

  • Full CSS/JavaScript support

Cons

  • Monthly cost (though often cheaper than self-hosting)

  • Data leaves your servers (security consideration)

  • Dependency on third-party service

Verdict

✅ Use for: Production apps, teams focused on shipping features, variable load

❌ Avoid for: Offline-only requirements, extreme data sensitivity


Method 5: No-Code/Low-Code Automation

Best for: Non-developers, business automation, workflow integration

Popular tools: Zapier, Make, n8n + PDF APIs

How It Works

No-code platforms connect triggers (form submissions, database changes, scheduled events) to PDF generation without writing code.

Example: N8n Workflow

  1. Trigger: New row in Google Sheets

  2. Action: Format data into HTML template

  3. Action: Call PDFRise API to generate PDF

  4. Action: Send PDF via Gmail

Example: Make (Integromat) Scenario

Form submission → HTML template → PDF API → Save to Google Drive → Email notification

Pros

  • No coding required

  • Quick setup (hours, not weeks)

  • Integrates with existing tools

  • Empowers non-technical teams

Cons

  • Limited customization

  • Platform costs add up

  • Complex logic is harder to implement

  • Debugging can be opaque

Verdict

✅ Use for: Business process automation, invoices from forms, certificates

❌ Avoid for: High customization needs, developer-heavy workflows


Comparison Table: Which Method Should You Choose?

Method

CSS Support

Setup Time

Scalability

Cost

Best For

Client-side JS

Limited

Hours

N/A

Free

Simple docs, prototypes

Server PDF libs

None (manual)

Days-Weeks

Manual

Free

Data reports, invoices

Headless browsers

Full

Days

Complex

Infra cost

Self-hosted, full control

PDF APIs

Full

30 min

Automatic

$/month

Production apps, teams

No-code

Full

Hours

Automatic

$/task

Business automation

Tags
pdf generation generate pdf from text programmatic pdf generation pdf automation document generation
About the Author
Subham Jobanputra

Subham Jobanputra