PDF生成 API vs ライブラリ徹底比較:どちらを選ぶべきか【2026年版】
PDF生成はWebアプリケーション開発で避けて通れない要件です。請求書、レポート、契約書、証明書——あらゆるビジネスシーンでPDF出力が求められます。
このとき、大きく分けて2つのアプローチがあります。
- ライブラリ方式 — 自分のサーバーにPDF生成ライブラリを組み込む
- API方式 — クラウドのPDF生成APIにHTTPリクエストを送る
どちらにもメリット・デメリットがあり、プロジェクトの要件によって最適解は変わります。この記事では両方のアプローチを深く掘り下げ、判断基準を明確にします。
ライブラリ方式の概要
PDF生成ライブラリは長い歴史があり、多くの開発者にとって馴染みのある選択肢です。代表的なものを見てみましょう。
主要なPDF生成ライブラリ
| ライブラリ | 言語 | 方式 |
|---|---|---|
| Puppeteer | Node.js | Headless Chromeを操作してHTML→PDF変換 |
| wkhtmltopdf | CLI | QtWebKitベースの変換ツール(2023年アーカイブ) |
| pdfkit | Node.js | プログラムでPDFを直接構築 |
| jsPDF | JavaScript | ブラウザ/Node.jsでPDF生成 |
| TCPDF | PHP | PHPの定番PDF生成ライブラリ |
| ReportLab | Python | Python向けPDF生成(商用ライセンスあり) |
| Prawn | Ruby | Ruby向けPDF生成 |
ライブラリ方式のメリット
完全な制御が可能 ライブラリはすべて自分のインフラで動くため、レンダリングプロセスを完全にコントロールできます。カスタムフォントの配置、特殊な用紙サイズ、独自のヘッダー/フッター処理など、細かな調整が自在です。
外部依存がない ネットワーク越しの通信が発生しないため、オフライン環境でも動作します。外部サービスの障害に影響を受けることもありません。
ランニングコストが明確 API利用料が発生しないため、自社サーバーのコストだけで済みます。月間生成数が少ない場合はコスト面で有利です。
ライブラリ方式のデメリット
セットアップと保守が大変
Puppeteerを例にとると、Headless Chromeのインストール、フォントのプロビジョニング、メモリ管理、プロセスのクリーンアップなど、考慮すべき点が多数あります。
// Puppeteerでの請求書PDF生成
const puppeteer = require('puppeteer');
async function generateInvoice(html) {
// Chromeプロセスの起動(メモリ消費大)
const browser = await puppeteer.launch({
headless: 'new',
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage', // Docker環境で必須
'--font-render-hinting=none',
],
});
try {
const page = await browser.newPage();
await page.setContent(html, { waitUntil: 'networkidle0' });
const pdf = await page.pdf({
format: 'A4',
margin: { top: '20mm', bottom: '20mm', left: '15mm', right: '15mm' },
printBackground: true,
});
return pdf;
} finally {
await browser.close(); // クリーンアップ必須
}
}
日本語・CJKフォントの問題
Linux環境では日本語フォントが入っていないことが多く、「豆腐」(□□□)になるトラブルが頻発します。Dockerイメージにフォントをバンドルする必要があり、イメージサイズが肥大化します。
# Dockerfileでのフォント対応例
FROM node:20-slim
# 日本語フォントのインストール(+200MB以上)
RUN apt-get update && apt-get install -y \
fonts-noto-cjk \
fonts-noto-cjk-extra \
&& rm -rf /var/lib/apt/lists/*
スケーリングが難しい
Headless Chromeは1プロセスあたり100MB以上のメモリを消費します。同時10リクエストで1GB以上のメモリが必要になり、サーバーリソースの見積もりが複雑です。負荷に応じたオートスケーリングの仕組みも自前で構築する必要があります。
API方式の概要
PDF生成APIは、HTTPリクエストでHTMLやテンプレートを送信し、PDFバイナリを受け取るクラウドサービスです。インフラの管理を外部に委託することで、開発者はアプリケーションのロジックに集中できます。
API方式のメリット
セットアップがほぼ不要
APIキーを取得してHTTPリクエストを送るだけで、すぐにPDF生成を始められます。
# curlで即座にPDF生成(FUNBREW PDFの例)
curl -X POST https://pdf.funbrew.cloud/api/v1/generate \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"html": "<h1>請求書</h1><p>合計: ¥100,000</p>",
"options": {
"format": "A4",
"margin": { "top": "20mm", "bottom": "20mm" }
}
}' \
--output invoice.pdf
レンダリング品質が安定
API側でブラウザエンジン、フォント、レンダリング設定が最適化されており、環境による差異が発生しません。FUNBREW PDFのように日本語フォントを内蔵しているAPIなら、CJK問題も解消されます。
スケーリングが自動
月100件でも月100万件でも、同じAPIコールで対応できます。インフラのスケーリングはAPI側が行うため、開発者はサーバーリソースの心配をする必要がありません。
多言語対応
REST APIなので、どのプログラミング言語からでも呼び出せます。Node.js、Python、PHP、Ruby、Go——言語を問わず同じAPIを使えるのは、複数サービスを運用するチームにとって大きなメリットです。
API方式のデメリット
コストが発生する
API利用には料金がかかります。ただし、ライブラリ方式で必要なサーバーリソース・運用工数と比較すると、トータルコストでは逆転するケースも多いです。各APIの料金比較も参考にしてください。
ネットワーク依存
HTTPリクエストが必要なため、完全なオフライン環境では使えません。また、ネットワーク遅延が加算されます(ただし、レンダリング自体が高速なため、体感速度は十分実用的です)。
データプライバシーの考慮
HTMLコンテンツを外部サーバーに送信するため、極めて機密性の高いデータを扱う場合は社内ポリシーの確認が必要です。
比較表:API vs ライブラリ
| 項目 | ライブラリ方式 | API方式 |
|---|---|---|
| 初期セットアップ | 数時間〜数日 | 数分 |
| レンダリング品質 | 環境依存 | 安定 |
| 日本語/CJK対応 | 要フォント設定 | 内蔵済み(APIによる) |
| スケーリング | 自前構築 | 自動 |
| コストモデル | サーバー費用 | API利用料 |
| 保守負担 | 高い(OS・ライブラリ更新) | 低い |
| オフライン動作 | 可能 | 不可 |
| 導入言語 | ライブラリ依存 | 任意 |
判断フレームワーク:どちらを選ぶべきか
ライブラリ方式が適しているケース
- シンプルなPDF:テキストと表だけの単純なレイアウト
- CJK不要:英語のみのドキュメント
- 低ボリューム:月に数十件程度の生成
- データローカリティ必須:規制上、外部送信が不可能な環境
- 既存資産がある:すでにPuppeteer等で安定稼働している仕組みがある
API方式が適しているケース
- 複雑なレイアウト:CSSグリッド、Flexbox、背景画像を多用するデザイン
- 日本語テキスト:CJKフォントの取り扱いが必要
- 高ボリューム:月間数千〜数百万件の生成
- 多言語チーム:Node.js、Python、PHPなど複数言語で同じPDF生成を行う
- 素早い立ち上げ:MVPやプロトタイプで即座にPDF機能が欲しい
ライブラリからAPIへの移行パス
既存のPuppeteerベースのPDF生成をAPIに移行する場合、HTMLテンプレート部分はそのまま再利用できます。変更が必要なのは「HTMLをPDFに変換する」部分だけです。
// Before: Puppeteerで生成(30行以上のコード)
const puppeteer = require('puppeteer');
const browser = await puppeteer.launch({ /* 設定... */ });
const page = await browser.newPage();
await page.setContent(html, { waitUntil: 'networkidle0' });
const pdf = await page.pdf({ format: 'A4', printBackground: true });
await browser.close();
// After: APIで生成(5行)
const response = await fetch('https://pdf.funbrew.cloud/api/v1/generate', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({ html, options: { format: 'A4' } }),
});
const pdf = await response.arrayBuffer();
Puppeteerからの詳しい移行手順はPuppeteer→PDF API移行ガイドをご覧ください。
コード比較:同じ請求書を生成する
実際に同じ請求書テンプレートを、ライブラリ方式とAPI方式の両方で生成するコードを比較します。
Puppeteer(ライブラリ方式)
const puppeteer = require('puppeteer');
async function generateInvoicePdf(invoiceData) {
const html = buildInvoiceHtml(invoiceData); // HTMLテンプレート生成
const browser = await puppeteer.launch({
headless: 'new',
args: ['--no-sandbox', '--disable-setuid-sandbox'],
});
const page = await browser.newPage();
await page.setContent(html, { waitUntil: 'networkidle0' });
const pdfBuffer = await page.pdf({
format: 'A4',
margin: { top: '20mm', right: '15mm', bottom: '20mm', left: '15mm' },
printBackground: true,
displayHeaderFooter: true,
headerTemplate: '<span></span>',
footerTemplate: '<div style="font-size:8px;text-align:center;width:100%;">Page <span class="pageNumber"></span></div>',
});
await browser.close();
return pdfBuffer;
}
FUNBREW PDF API(API方式)
async function generateInvoicePdf(invoiceData) {
const html = buildInvoiceHtml(invoiceData); // 同じHTMLテンプレートを使用
const response = await fetch('https://pdf.funbrew.cloud/api/v1/generate', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.FUNBREW_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
html,
options: {
format: 'A4',
margin: { top: '20mm', right: '15mm', bottom: '20mm', left: '15mm' },
printBackground: true,
},
}),
});
return await response.arrayBuffer();
}
HTMLテンプレートの buildInvoiceHtml() はまったく同じものを使えます。変更点はPDF変換処理の部分だけです。Playgroundで実際にHTMLを入力してPDF出力を試すこともできます。
Python(ReportLab vs API)
# ReportLab — Pythonでプログラム的にPDFを構築
from reportlab.lib.pagesizes import A4
from reportlab.pdfgen import canvas
def generate_invoice(data, output_path):
c = canvas.Canvas(output_path, pagesize=A4)
c.setFont("Helvetica-Bold", 20)
c.drawString(50, 780, "INVOICE")
c.setFont("Helvetica", 12)
c.drawString(50, 750, f"Invoice #: {data['number']}")
c.drawString(50, 730, f"Date: {data['date']}")
# ... 座標を計算しながら1行ずつ配置
c.save()
# FUNBREW PDF API — HTMLテンプレートでPDF生成
import requests
def generate_invoice(data):
html = render_template("invoice.html", data=data)
response = requests.post(
"https://pdf.funbrew.cloud/api/v1/generate",
headers={"Authorization": f"Bearer {API_KEY}"},
json={"html": html, "options": {"format": "A4"}},
)
return response.content
ReportLabは座標ベースでPDFを構成するため、レイアウト変更のたびに座標計算のやり直しが必要です。HTML/CSSベースのAPIなら、デザインの修正はCSSの変更だけで完結します。CSSによるPDFスタイリングのコツはHTML to PDF CSSテクニック集を参照してください。
まとめ
PDF生成のAPI方式とライブラリ方式は、どちらかが絶対的に優れているわけではありません。
- 小規模・英語のみ・既存資産あり → ライブラリ方式を継続
- 日本語対応・スケーラビリティ・開発速度 → API方式が有利
プロジェクトの初期段階であれば、まずAPIで素早くMVPを構築し、特殊な要件が見えてきた段階でライブラリへの移行を検討する——という進め方も実用的です。
FUNBREW PDFは無料プランから試せるので、まずはPlaygroundで実際のPDF出力を確認してみてください。各言語のセットアップ方法はクイックスタートガイドにまとめています。
関連記事
- HTML to PDF API比較 2026年版 — API同士の比較
- Puppeteer→PDF API移行ガイド — Puppeteerからの移行手順
- HTML to PDF完全ガイド — HTML→PDF変換の包括的な解説
- PDF API本番運用ガイド — 本番環境でのベストプラクティス