How to Generate PDF from Text Programmatically: 5 Methods Compared for 2026
Subham Jobanputra
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
Trigger: New row in Google Sheets
Action: Format data into HTML template
Action: Call PDFRise API to generate PDF
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 |