はじめに
「Webアプリから請求書や納品書のPDFを出力したいけれど、レイアウト調整をコードでゴリゴリ書くのはつらい…」「帳票のデザイン変更のたびに開発者が呼び出されるのをなんとかしたい…」
そんな悩みを抱えたことはありませんか?PDF生成は多くの業務システムで避けて通れない機能ですが、座標指定を手書きするライブラリは保守が大変ですし、商用の帳票ツールはライセンス費用が悩みの種です。
そこで注目したいのが「pdfme」です。TypeScriptとReactで作られたオープンソースのPDF生成ライブラリで、JSONベースのテンプレートとWYSIWYGテンプレートデザイナーを組み合わせることで、「デザインは画面上でドラッグ&ドロップ、生成はコード一発」という理想的な分業を実現できます。日本発のプロジェクトとしても知られており、この記事では基本から実践的な使い方まで解説します。
pdfmeとは
pdfmeは、TypeScriptで書かれたオープンソースのPDF生成ライブラリです。ブラウザとNode.jsの両方で動作し、MITライセンスで商用利用も無料です。GitHubで4,600以上のスターを獲得しており、2026年7月時点の最新メジャーバージョンは6.xです。
最大の特徴は、「固定部分のPDF(basePdf)」と「可変部分の定義(schemas)」を分離したテンプレート設計にあります。テンプレートはただのJSONなので、データベースに保存したり、APIでやり取りしたりするのも簡単です。
主な特徴
- JSONベースのテンプレート - レイアウト定義がプレーンなJSONなので、保存・共有・バージョン管理が容易です
- WYSIWYGテンプレートデザイナー - ドラッグ&ドロップでテンプレートを編集できるデザイナーUIを、自分のアプリにそのまま組み込めます
- ブラウザ・Node.js両対応 - フロントエンドでのプレビュー生成も、サーバーサイドでのバッチ生成も同じコードで書けます
- 豊富なスキーマ(プラグイン) - テキスト、画像、SVG、テーブル、QRコードをはじめとする各種バーコード、日付、チェックボックスなどが公式プラグインとして用意されています
- 完全無料 - MITライセンスのため、商用の帳票システムにも安心して導入できます
パッケージ構成
pdfmeは機能ごとにパッケージが分かれており、必要なものだけをインストールできます。
| パッケージ | 役割 |
|---|---|
@pdfme/common |
テンプレート型定義などの共通機能 |
@pdfme/generator |
PDF生成エンジン |
@pdfme/ui |
Designer / Form / Viewer のUIコンポーネント |
@pdfme/schemas |
画像・テーブル・バーコードなどの拡張スキーマ |
インストール
PDF生成だけを行う場合は、次の2つをインストールします。
# npm
npm install @pdfme/generator @pdfme/common
# pnpm
pnpm add @pdfme/generator @pdfme/common
# yarn
yarn add @pdfme/generator @pdfme/common
デザイナーやフォームなどのUIを使う場合は @pdfme/ui を、画像やQRコードなどの拡張スキーマを使う場合は @pdfme/schemas を追加します。
npm install @pdfme/ui @pdfme/schemas
基本的な使い方
pdfmeでのPDF生成は「テンプレートを定義して、データを流し込む」の2ステップだけです。まずは白紙のPDFにテキストを配置する最小構成から見てみましょう。
import { BLANK_PDF, type Template } from '@pdfme/common';
import { generate } from '@pdfme/generator';
// テンプレート = 固定部分(basePdf) + 可変部分(schemas)
const template: Template = {
basePdf: BLANK_PDF, // 白紙のA4。既存PDFをbase64で渡すことも可能
schemas: [
// 1ページ目に配置するフィールドの配列
[
{
name: 'title',
type: 'text',
position: { x: 20, y: 20 }, // 単位はmm
width: 120,
height: 12,
fontSize: 20,
},
{
name: 'body',
type: 'text',
position: { x: 20, y: 40 },
width: 170,
height: 60,
fontSize: 12,
},
],
],
};
// フィールド名をキーにしてデータを流し込む
const inputs = [
{
title: 'pdfmeで作る初めてのPDF',
body: 'テンプレートにデータを流し込むだけでPDFが完成します。',
},
];
generate({ template, inputs }).then((pdf) => {
// ブラウザならBlobにして表示
const blob = new Blob([pdf.buffer], { type: 'application/pdf' });
window.open(URL.createObjectURL(blob));
});
ポイントは inputs が配列であることです。配列の要素を増やせば、同じテンプレートから複数件分のPDFをまとめて生成できます。宛名違いの請求書を100件一括生成する、といった処理も inputs に100要素渡すだけです。
Node.jsで実行する場合は、生成結果をそのままファイルに書き出せます。
import fs from 'node:fs';
const pdf = await generate({ template, inputs });
fs.writeFileSync('output.pdf', pdf);
QRコードや画像を埋め込む
@pdfme/schemas のプラグインを使うと、テキスト以外の要素も扱えます。
import { BLANK_PDF, type Template } from '@pdfme/common';
import { generate } from '@pdfme/generator';
import { text, image, barcodes } from '@pdfme/schemas';
const template: Template = {
basePdf: BLANK_PDF,
schemas: [
[
{ name: 'productName', type: 'text', position: { x: 20, y: 20 }, width: 100, height: 10 },
{ name: 'productPhoto', type: 'image', position: { x: 20, y: 40 }, width: 60, height: 40 },
{ name: 'productUrl', type: 'qrcode', position: { x: 140, y: 40 }, width: 40, height: 40 },
],
],
};
const plugins = { text, image, qrcode: barcodes.qrcode };
const inputs = [
{
productName: 'pdfme公式ドキュメント',
productPhoto: 'data:image/png;base64,iVBORw0KGgo...', // base64形式の画像
productUrl: 'https://pdfme.com/',
},
];
const pdf = await generate({ template, inputs, plugins });
QRコード以外にも、EAN-13やCODE128といった各種バーコードが barcodes に含まれています。商品ラベルや検品票の生成にそのまま使えます。
実践的なユースケース
テンプレートデザイナーをアプリに組み込む
pdfmeの真価は @pdfme/ui のDesignerにあります。ドラッグ&ドロップでフィールドを配置できるエディタ画面を、数行のコードで自分のアプリに埋め込めるのです。
import { BLANK_PDF, type Template } from '@pdfme/common';
import { Designer } from '@pdfme/ui';
import { text, image, barcodes } from '@pdfme/schemas';
const domContainer = document.getElementById('designer-container')!;
const designer = new Designer({
domContainer,
template: {
basePdf: BLANK_PDF,
schemas: [[]], // 空のテンプレートから編集開始
},
plugins: { text, image, qrcode: barcodes.qrcode },
});
// 編集内容が変わるたびにテンプレートを保存できる
designer.onChangeTemplate((updatedTemplate: Template) => {
localStorage.setItem('my-template', JSON.stringify(updatedTemplate));
});
これで「帳票のレイアウト変更は業務部門の担当者がデザイナー画面で行い、開発者は保存されたJSONテンプレートで生成するだけ」という運用が実現します。デザイン変更のたびにコードを修正してデプロイする必要はもうありません。
入力フォームとプレビューを組み合わせる
DesignerのほかにFormとViewerも用意されています。Formはテンプレートのレイアウトそのままに入力欄を表示するコンポーネントで、「PDFの完成形を見ながら入力してもらう」UIが簡単に作れます。
import { Form } from '@pdfme/ui';
import { generate } from '@pdfme/generator';
const form = new Form({
domContainer: document.getElementById('form-container')!,
template, // Designerで作ったテンプレートをそのまま使う
inputs: [{ title: '', body: '' }],
});
// ダウンロードボタンのクリックで、入力内容からPDFを生成
document.getElementById('download-btn')!.addEventListener('click', async () => {
const pdf = await generate({ template, inputs: form.getInputs() });
const blob = new Blob([pdf.buffer], { type: 'application/pdf' });
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = 'document.pdf';
link.click();
});
既存のPDFをテンプレートにする
basePdf には既存のPDFをbase64文字列やArrayBufferで渡せます。会社指定の申請書や公的な様式など「決まったフォーマットの決まった位置に文字を差し込みたい」ケースで威力を発揮します。
import fs from 'node:fs';
import { generate } from '@pdfme/generator';
// 既存の様式PDFを読み込んでbasePdfに指定
const basePdf = fs.readFileSync('application-form.pdf');
const template = {
basePdf,
schemas: [
[
{ name: 'applicantName', type: 'text', position: { x: 45, y: 62 }, width: 80, height: 8 },
{ name: 'applicationDate', type: 'text', position: { x: 140, y: 30 }, width: 50, height: 8 },
],
],
};
const pdf = await generate({
template,
inputs: [{ applicantName: '山田 太郎', applicationDate: '2026年7月14日' }],
});
fs.writeFileSync('filled-form.pdf', pdf);
座標を手で調べるのが面倒な場合も心配ありません。Designerで様式PDFを読み込めば、画面上で位置を合わせてテンプレートJSONを出力できます。
まとめ
pdfmeについて、基本から実践的な使い方まで解説しました。ポイントを振り返ります。
- pdfmeはTypeScript製のオープンソースPDF生成ライブラリで、MITライセンスにより商用でも無料で使えます
- テンプレートは「basePdf + schemas」のJSONで表現され、
generate({ template, inputs })だけでPDFが完成します @pdfme/uiのDesignerを組み込めば、非エンジニアでも帳票レイアウトを編集できる運用が実現します- 画像・QRコード・バーコード・テーブルなど豊富なスキーマが公式提供されており、ブラウザでもNode.jsでも同じコードで動きます
まずは公式のプレイグラウンドでデザイナーの操作感を試してみてください。「これなら帳票運用を任せられる」と実感できるはずです。そのうえで、この記事のコード例をベースに、あなたのアプリへのPDF生成機能の組み込みに挑戦してみましょう。