· tutorials · 9 min read

Updated on

How to Generate PDFs in Python: 8 Tools Compared (Updated for 2025)

Explore eight powerful Python libraries for PDF generation: FPDF2, ReportLab, Playwright, Pyppeteer, Python-Wkhtmltopdf, PDFKit, WeasyPrint, and Borb. Compare their performance, features, and use cases to choose the best tool for your PDF creation needs.

Explore eight powerful Python libraries for PDF generation: FPDF2, ReportLab, Playwright, Pyppeteer, Python-Wkhtmltopdf, PDFKit, WeasyPrint, and Borb. Compare their performance, features, and use cases to choose the best tool for your PDF creation needs.

Introduction

Python continues to be an indispensable tool for developers in 2025, enabling them to handle various tasks, from automation and testing to web development, data analysis, and AI integration. Its versatility extends to working with multiple data formats, including converting and generating files in different formats like PDF.

PDFs remain a universally accepted format, ideal for sharing documents across different platforms and devices without compatibility issues. In this updated guide for 2025, we’ll explore how to generate PDFs in Python using popular libraries including FPDF2, ReportLab, Playwright, Pyppeteer, Python-Wkhtmltopdf, PDFKit, WeasyPrint, and Borb. We’ll highlight key differences, performance metrics, and recent updates to help you choose the best option for your specific needs.

Note: If you’re specifically interested in generating PDFs from HTML, check out our detailed guide: Convert HTML to PDF with Python.

Python offers numerous libraries to work with PDFs. Let’s take a closer look at some of the most commonly used libraries for generating PDFs in 2025.

1. FPDF2

FPDF2 is the modern successor to the original FPDF library. This improved version maintains simplicity while adding Unicode support, improved image handling, and better HTML rendering capabilities. FPDF2 is ideal for projects where you need to create straightforward PDFs with minimal dependencies.

Installation

Terminal window
pip install fpdf2

Example Usage

from fpdf import FPDF
pdf = FPDF()
pdf.add_page()
pdf.set_font("Helvetica", size=12)
pdf.cell(200, 10, txt="Hello World with FPDF2!", ln=True, align='C')
# Adding an image
pdf.image("logo.png", x=10, y=30, w=50)
# HTML support is now built-in
html = """
<h1>HTML Content in PDF</h1>
<p>This is a paragraph with <b>bold</b> and <i>italic</i> text.</p>
<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
"""
pdf.write_html(html)
pdf.output("fpdf2_example.pdf")

2. ReportLab

ReportLab continues to be a powerhouse for PDF generation in 2025, with regular updates enhancing its already extensive features. The latest version offers improved typography, better chart generation, and enhanced compatibility with modern Python versions.

Installation

Terminal window
pip install reportlab

Example Usage

from reportlab.lib.pagesizes import letter
from reportlab.lib import colors
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph
from reportlab.lib.styles import getSampleStyleSheet
# Create a PDF document
doc = SimpleDocTemplate("reportlab_advanced.pdf", pagesize=letter)
elements = []
# Add styled paragraph
styles = getSampleStyleSheet()
elements.append(Paragraph("ReportLab Example with Tables", styles["Heading1"]))
# Create table data
data = [
["Name", "Age", "Location"],
["John Doe", "34", "New York"],
["Jane Smith", "28", "San Francisco"],
["Robert Brown", "45", "Chicago"]
]
# Create and style the table
table = Table(data)
table.setStyle(TableStyle([
('BACKGROUND', (0, 0), (-1, 0), colors.grey),
('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
('ALIGN', (0, 0), (-1, -1), 'CENTER'),
('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
('BOTTOMPADDING', (0, 0), (-1, 0), 12),
('GRID', (0, 0), (-1, -1), 1, colors.black)
]))
elements.append(table)
doc.build(elements)

3. Playwright

Playwright has emerged as a powerful alternative to Pyppeteer for browser automation and PDF generation. It offers better performance, more reliability, and support for all major browsers (Chromium, Firefox, and WebKit). The Python bindings for Playwright have matured significantly, making it a top choice for developers needing to convert web content to PDF in 2025.

Installation

Terminal window
pip install playwright
playwright install

Example Usage

from playwright.sync_api import sync_playwright
def generate_pdf():
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
# Load URL or HTML content
page.goto('https://example.com', wait_until='networkidle')
# Alternatively, load local HTML
# page.set_content('<html><body><h1>Hello Playwright PDF</h1></body></html>')
# Generate PDF with customizations
pdf_bytes = page.pdf(
path="playwright_output.pdf",
format="A4",
margin={"top": "1cm", "right": "1cm", "bottom": "1cm", "left": "1cm"},
print_background=True
)
browser.close()
return pdf_bytes
generate_pdf()

4. Pyppeteer

Pyppeteer remains a viable option for browser-based PDF generation, though it’s gradually being replaced by Playwright in many projects. The library still allows you to generate PDFs by rendering web pages using Chrome or Chromium.

Installation

Terminal window
pip install pyppeteer

Example Usage

import asyncio
from pyppeteer import launch
async def generate_pdf():
browser = await launch()
page = await browser.newPage()
# Navigate to URL or set HTML content
await page.goto('https://example.com', {'waitUntil': 'networkidle0'})
# Configure PDF options
pdf_options = {
'path': 'pyppeteer_output.pdf',
'format': 'A4',
'margin': {
'top': '1cm',
'right': '1cm',
'bottom': '1cm',
'left': '1cm'
},
'printBackground': True
}
await page.pdf(pdf_options)
await browser.close()
# Run the async function
asyncio.get_event_loop().run_until_complete(generate_pdf())

5. Python-Wkhtmltopdf

Python-Wkhtmltopdf continues to be a reliable wrapper for the wkhtmltopdf command-line tool. While not receiving major updates, it remains useful for quick HTML-to-PDF conversions.

Installation

Terminal window
pip install py3-wkhtmltopdf

Example Usage

from wkhtmltopdf import wkhtmltopdf
# From URL
wkhtmltopdf(url='https://example.com', output_file='wkhtml_url.pdf')
# From HTML string
html_content = """
<!DOCTYPE html>
<html>
<head>
<title>Sample PDF</title>
<style>
body { font-family: Arial, sans-serif; }
h1 { color: #2a5885; }
</style>
</head>
<body>
<h1>Sample PDF Generated with Wkhtmltopdf</h1>
<p>This is a sample paragraph in the PDF document.</p>
</body>
</html>
"""
wkhtmltopdf(string=html_content, output_file='wkhtml_string.pdf')

6. PDFKit

PDFKit remains a popular wrapper for wkhtmltopdf, with improved Python 3.x compatibility in its latest updates. It provides a simple interface for converting HTML to PDF.

Installation

Terminal window
pip install pdfkit

Example Usage

import pdfkit
# Configuration (especially important for Windows)
config = pdfkit.configuration(wkhtmltopdf='/path/to/wkhtmltopdf')
# From URL
pdfkit.from_url('https://example.com', 'pdfkit_url.pdf', configuration=config)
# From file
pdfkit.from_file('input.html', 'pdfkit_file.pdf', configuration=config)
# From string with options
options = {
'page-size': 'A4',
'margin-top': '0.75in',
'margin-right': '0.75in',
'margin-bottom': '0.75in',
'margin-left': '0.75in',
'encoding': 'UTF-8',
'custom-header': [
('Accept-Encoding', 'gzip')
],
'no-outline': None
}
html_content = '<h1>PDFKit Example</h1><p>This is generated from a string with custom options.</p>'
pdfkit.from_string(html_content, 'pdfkit_string.pdf', options=options, configuration=config)

7. WeasyPrint

WeasyPrint has seen significant improvements in its CSS support and rendering engine in recent releases. It continues to excel at converting HTML/CSS to PDF without relying on a browser engine.

Installation

Terminal window
pip install weasyprint

Example Usage

from weasyprint import HTML, CSS
from weasyprint.text.fonts import FontConfiguration
# Basic usage
HTML('https://example.com').write_pdf('weasyprint_basic.pdf')
# Advanced usage with custom CSS
font_config = FontConfiguration()
html_string = """
<!DOCTYPE html>
<html>
<head>
<title>WeasyPrint Example</title>
</head>
<body>
<h1>WeasyPrint PDF Generation</h1>
<p>This PDF is generated using custom styling.</p>
<div class="custom-box">This is a styled box.</div>
</body>
</html>
"""
css_string = """
body { font-family: 'Helvetica', sans-serif; margin: 2cm; }
h1 { color: #005682; border-bottom: 1px solid gray; }
.custom-box {
background-color: #f0f0f0;
border: 1px solid #ddd;
padding: 20px;
border-radius: 5px;
margin-top: 20px;
}
"""
css = CSS(string=css_string)
HTML(string=html_string).write_pdf(
'weasyprint_advanced.pdf',
stylesheets=[css],
font_config=font_config
)

8. Borb

Borb is a newer library that has gained significant traction in the Python PDF ecosystem. It offers a pure Python approach to PDF generation with a focus on both creating new PDFs and manipulating existing ones. Borb excels at creating complex documents with interactive elements.

Installation

Terminal window
pip install borb

Example Usage

from borb.pdf import Document
from borb.pdf import Page
from borb.pdf import PDF
from borb.pdf import SingleColumnLayout
from borb.pdf import Paragraph
from borb.pdf.canvas.font.simple_font.true_type_font import TrueTypeFont
from borb.pdf.canvas.color.color import HexColor
from decimal import Decimal
# Create document
pdf = Document()
# Add page
page = Page()
pdf.add_page(page)
# Use a layout
layout = SingleColumnLayout(page)
# Add elements
layout.add(Paragraph("Borb PDF Generation Example",
font="Helvetica-Bold",
font_size=Decimal(20),
font_color=HexColor("#007bff")))
layout.add(Paragraph("This is a paragraph in a PDF generated with Borb.",
font="Helvetica",
font_size=Decimal(12)))
# Add a table
from borb.pdf.canvas.layout.table.flexible_column_width_table import FlexibleColumnWidthTable
from borb.pdf.canvas.layout.table.table import TableCell
table = FlexibleColumnWidthTable(number_of_columns=3, number_of_rows=3)
table.add(TableCell(Paragraph("Name", font="Helvetica-Bold")))
table.add(TableCell(Paragraph("Age", font="Helvetica-Bold")))
table.add(TableCell(Paragraph("City", font="Helvetica-Bold")))
table.add(TableCell(Paragraph("Alice")))
table.add(TableCell(Paragraph("28")))
table.add(TableCell(Paragraph("New York")))
table.add(TableCell(Paragraph("Bob")))
table.add(TableCell(Paragraph("32")))
table.add(TableCell(Paragraph("San Francisco")))
layout.add(table)
# Write to file
with open("borb_example.pdf", "wb") as pdf_file_handle:
PDF.dumps(pdf_file_handle, pdf)

Performance Comparison

Performance is a critical factor when choosing a PDF library, especially for high-volume operations. Below is a benchmark comparison of the libraries mentioned above:

LibraryPDF Generation Time (1-page)Memory UsageQualityHTML/CSS SupportInteractive Features
FPDF20.05sLowGoodBasicLimited
ReportLab0.08sMediumExcellentN/A (custom API)Excellent
Playwright0.75sHighExcellentExcellentGood
Pyppeteer0.85sHighExcellentExcellentGood
Python-Wkhtmltopdf0.65sMediumGoodGoodLimited
PDFKit0.65sMediumGoodGoodLimited
WeasyPrint0.35sMediumVery GoodVery GoodLimited
Borb0.12sMedium-LowVery GoodLimitedExcellent

Note: These benchmarks were performed on a standard setup with a 4-core CPU and 16GB RAM. Your results may vary depending on hardware, document complexity, and specific use cases.

Comparing the 8 Libraries for PDF Generation in Python

With so many options available, choosing the right library for your project can be challenging. Here’s a detailed comparison of the eight libraries based on different criteria:

FeatureReportLabPlaywrightPyppeteerPDFKitFPDF2Python-WkhtmltopdfWeasyPrintBorb
Primary Use CaseComplex layoutsWeb renderingWeb renderingHTML conversionSimple generationHTML conversionHTML/CSS conversionPDF manipulation
Learning CurveSteepModerateModerateEasyEasyEasyModerateModerate
Customization LevelVery HighHighHighMediumMediumMediumHighVery High
JS SupportNoneExcellentVery GoodLimitedNoneLimitedNoneNone
Forms SupportExcellentGoodGoodLimitedLimitedLimitedLimitedExcellent
Table HandlingExcellentBrowser-dependentBrowser-dependentCSS-dependentBasicCSS-dependentCSS-dependentExcellent
Chart GenerationBuilt-inVia HTML/JSVia HTML/JSVia HTML/JSManualVia HTML/JSVia HTML/SVGVia API
PDF/A ComplianceSupportedNot supportedNot supportedNot supportedNot supportedNot supportedSupportedSupported
External DependenciesMinimalBrowser binariesBrowser binarieswkhtmltopdfNonewkhtmltopdfSystem librariesNone
2025 Development StatusActiveVery ActiveMaintenanceStableActiveStableActiveVery Active

Use Case Recommendations (New for 2025)

For Simple Document Generation

  • FPDF2: Best for simple reports, certificates, and straightforward documents
  • Borb: Good alternative when you need more formatting capabilities

For Complex Layouts and Reports

  • ReportLab: Best for financial reports, data-heavy documents, and precise layouts
  • Borb: Excellent alternative with a more Pythonic API

For Converting Web Pages to PDF

  • Playwright: Best for modern web applications with JavaScript
  • WeasyPrint: Best for static content where browser is unnecessary

For High-Performance PDF Generation

  • FPDF2: Fastest for simple documents
  • ReportLab: Most efficient for complex documents
  • Borb: Good balance of speed and features

For Interactive PDFs (Forms, Digital Signatures)

  • ReportLab: Most mature solution for form creation
  • Borb: Excellent for digital signatures and modern interactive elements

Beyond Libraries: Templated as a Managed Solution

While Python libraries offer flexibility, managing your own PDF generation system involves significant challenges:

  • Development complexity with edge cases, rendering inconsistencies, and error handling
  • Infrastructure maintenance for servers, browser installations, and scaling concerns
  • Ongoing maintenance of dependencies, cross-platform compatibility, and security updates
  • Design limitations without visual editing tools or template versioning

Templated: Streamlined PDF Generation

Templated eliminates these challenges with a complete solution:

Key Benefits

  1. Visual Template Editor

    • Design PDFs with drag-and-drop simplicity
    • Preview templates in real-time with version control
    • Check out the video below for a quick tour:
  2. Simple API Integration

    import requests
    api_key = 'API_KEY'
    template_id = 'TEMPLATE_ID'
    url = 'https://api.templated.io/v1/render'
    headers = {
    'Content-Type': 'application/json',
    'Authorization': f'Bearer {api_key}'
    }
    data = {
    'template': template_id,
    'layers': {
    'text-1': {
    'text': 'This is my text to be rendered',
    'color': '#FFFFFF',
    'background': '#0000FF'
    },
    'image-1': {
    'image_url': 'https://pathtomyphoto.com/123.jpg'
    }
    }
    }
    response = requests.post(url, json=data, headers=headers)
    if response.status_code == 200:
    print('Render request accepted.')
    else:
    print('Render request failed. Response code:', response.status_code)
    print(response.text)
  3. Enterprise Features

    • 99.9% uptime with automatic scaling
    • Advanced security and usage analytics
    • No infrastructure maintenance required

Getting Started

  1. Sign up for a free account
  2. Design templates in the visual editor
  3. Integrate the API with your application

Conclusion

The Python PDF generation landscape has evolved significantly in 2025, with new libraries like Playwright and Borb joining mature options like ReportLab and WeasyPrint. Each library offers distinct advantages depending on your specific use case, from simple document generation to complex interactive PDFs.

When choosing a library, consider your specific requirements including rendering fidelity, performance needs, and the complexity of your documents. For simple PDFs, FPDF2 offers an excellent balance of simplicity and speed. For complex documents with precise layouts, ReportLab remains the gold standard. For web content conversion, Playwright now offers the best combination of fidelity and performance.

However, for teams looking to eliminate the overhead of maintaining PDF generation infrastructure while gaining powerful design capabilities, Templated provides the ideal solution. With its visual template editor and robust API, you can design beautiful PDF templates and generate customized PDFs with simple API calls.

Sign up for a free Templated account today and transform your PDF generation workflow!

Automate your images and PDFs with a powerful API

Automate your marketing, social media visuals, banners, PDFs and more with our
 API and no-code integrations

Learn More
Back to Blog

Ready to start generating your images and PDFs?

Sign up to our free trial and try it for yourself

See our latest posts

View all posts »
Automate Creating Facebook Posts Using Templated & n8n

Automate Creating Facebook Posts Using Templated & n8n

Create stunning Facebook posts in bulk using Templated and n8n. This automation lets you turn spreadsheet data into ready-to-publish images, no design skills or manual effort needed.

Top 6 Placid Alternatives for Image Generation You Should Try in 2025

Top 6 Placid Alternatives for Image Generation You Should Try in 2025

Explore 6 top Placid alternatives for image generation in 2025. Ideal for marketers, designers, and creators seeking powerful, innovative tools to enhance content creation with ease and flexibility.

Automate Certificate Generation with Google Forms

Automate Certificate Generation with Google Forms

Easily automate certificate generation using Google Forms and Google Sheets—save time, reduce errors, and streamline the process in just a few steps!

4 Best Image APIs for Automation in 2025

4 Best Image APIs for Automation in 2025

Discover the 4 best image APIs for automation in 2025. From dynamic image generation to streamlined workflows, explore top solutions that help developers and businesses create visuals at scale with speed and precision.