ai-pdf-builder
v0.6.2
Published
AI-powered PDF generator for legal docs, pitch decks, and reports. SAFEs, NDAs, term sheets, whitepapers from Markdown. Works with Claude, Cursor, GPT, Copilot, OpenClaw agents. npx ai-pdf-builder
Maintainers
Keywords
Readme
ai-pdf-builder
🤖 AI-Powered Professional PDF Generation — Create beautiful business documents with AI or from Markdown. Generate whitepapers, memos, agreements, and term sheets instantly. Perfect for AI agents, chatbots, and automation workflows.
New in v0.4: AI document generation! Just describe what you need and let Claude create professional PDFs automatically.
Works With
Perfect For
- 🤖 AI Agents & Chatbots — Generate documents on-the-fly from conversational AI
- ⚖️ Legal Tech — Automate NDA, contract, and agreement generation
- 💰 Fintech — Create term sheets, SAFEs, and investment documents programmatically
- 🔄 Automation Workflows — Integrate with n8n, Zapier, Make, or custom pipelines
- 📱 Messaging Bots — Let users request documents via Telegram, WhatsApp, Discord, Slack, or Signal
- 🏢 Enterprise — Bulk document generation with consistent branding
Table of Contents
- Works With
- Perfect For
- Features
- 🤖 AI Generation (NEW!)
- Prerequisites
- Installation
- Quick Start
- Usage Examples
- Integration with Next.js
- API Reference
- Built-in Templates
- Troubleshooting
- Error Handling
- TypeScript Best Practices
- Advanced Topics
- Production Deployment
- FAQ
- Integrations
- License
- Contributing
Features
- 🤖 AI Document Generation: Describe what you need → get a professional PDF (powered by Claude)
- Company-Aware AI: Use
--companyto auto-include your company details in generated docs - Multiple Document Types: Built-in templates for memos, agreements, term sheets, and whitepapers
- Custom Styling: Apply custom colors and branding to any template
- TypeScript Support: Full type definitions included
- Flexible Output: Get PDF as Buffer or save directly to file
- Template System: Use built-in templates or register your own
- Security: Built-in content sanitization for LaTeX safety
🤖 AI Generation (NEW!)
Generate professional documents by describing what you need. No Markdown required!
Quick AI Examples
# Generate a business memo
npx ai-pdf-builder ai "Write a memo about Q1 2026 hiring plans" -o hiring-memo.pdf
# Generate with your company branding (reads from company.json)
npx ai-pdf-builder ai "Create an NDA for a potential partner" --company -o nda.pdf
# Generate a whitepaper
npx ai-pdf-builder ai "Write a technical whitepaper about AI in fintech" --template whitepaper -o whitepaper.pdf
# Generate a term sheet
npx ai-pdf-builder ai "Create a Series A term sheet for a $5M raise at $20M pre-money" --template termsheet -o termsheet.pdfThe --company Flag
Create a company.json file in your project root with your company details:
{
"name": "Acme Corp",
"legalName": "Acme Corporation Inc.",
"address": "123 Main St, San Francisco, CA 94102",
"website": "https://acme.com",
"industry": "Enterprise Software",
"description": "We build productivity tools for modern teams."
}Then use --company to automatically inject these details:
# AI knows your company context
npx ai-pdf-builder ai "Write an investor update for Q4" --company -o q4-update.pdf
npx ai-pdf-builder ai "Create a partnership proposal" --company -o proposal.pdfAI CLI Options
| Flag | Description |
|------|-------------|
| --company, -c | Load company context from company.json |
| --template, -t | Use specific template (memo, agreement, termsheet, whitepaper) |
| --output, -o | Output file path |
| --model | Claude model to use (default: claude-sonnet-4-20250514) |
| --verbose, -v | Show AI generation progress |
Programmatic AI Generation
import { generateWithAI } from 'ai-pdf-builder';
// Simple AI generation
const result = await generateWithAI({
prompt: "Write a professional memo about remote work policy changes",
template: "memo",
metadata: {
title: "Remote Work Policy Update",
author: "HR Department"
}
});
// With company context
const result = await generateWithAI({
prompt: "Create an advisor agreement",
template: "agreement",
companyContext: {
name: "Acme Corp",
legalName: "Acme Corporation Inc."
}
});
if (result.success) {
fs.writeFileSync('output.pdf', result.buffer);
}Requirements for AI Generation
- Anthropic API Key: Set
ANTHROPIC_API_KEYenvironment variable - Pandoc and LaTeX (same as regular PDF generation)
Prerequisites
This package requires Pandoc and LaTeX to be installed on your system:
macOS
# Install Pandoc
brew install pandoc
# Install BasicTeX (minimal LaTeX)
brew install --cask basictex
# After installing BasicTeX, install required packages
sudo tlmgr update --self
sudo tlmgr install collection-fontsrecommended fancyhdr titlesec enumitem xcolor booktabs longtable geometry hyperref setspace array multirow listingsUbuntu/Debian
# Install Pandoc and TeX Live
sudo apt-get update
sudo apt-get install -y pandoc texlive-latex-base texlive-latex-extra texlive-fonts-recommendedWindows
Docker
For containerized environments, use a Pandoc/LaTeX image:
FROM pandoc/latex:latestInstallation
npm install ai-pdf-builderOr with yarn:
yarn add ai-pdf-builderFor AI Generation
Set your Anthropic API key:
export ANTHROPIC_API_KEY="your-api-key"Or add to .env:
ANTHROPIC_API_KEY=your-api-keyQuick Start
AI Generation (Easiest!)
# One command to generate a professional PDF
npx ai-pdf-builder ai "Write a business proposal for a SaaS product" -o proposal.pdfFrom Markdown
import { generatePDF } from 'ai-pdf-builder';
import * as fs from 'fs';
const result = await generatePDF({
content: '# My Document\n\nThis is the content of my PDF.',
metadata: {
title: 'My First PDF',
author: 'John Doe',
date: 'January 2026'
}
});
if (result.success && result.buffer) {
fs.writeFileSync('output.pdf', result.buffer);
console.log(`PDF generated! Size: ${result.fileSize} bytes`);
}Usage Examples
AI-Generated Business Memo
# CLI - Instant memo generation
npx ai-pdf-builder ai "Write an executive memo about launching our new mobile app in Q2. Include timeline, resource needs, and risk factors." --template memo -o app-launch-memo.pdf
# With company context for branded output
npx ai-pdf-builder ai "Create a board update covering our Series A progress, key metrics, and next quarter goals" --company --template memo -o board-update.pdfAI-Generated Legal Documents
# NDA with your company details
npx ai-pdf-builder ai "Generate an NDA for sharing proprietary technology with a potential partner" --company -o tech-nda.pdf
# Advisor agreement
npx ai-pdf-builder ai "Create an advisor agreement offering 0.5% equity over 2 years with monthly vesting" --company --template agreement -o advisor-agreement.pdfBasic PDF Generation
import { generatePDF } from 'ai-pdf-builder';
const result = await generatePDF({
content: `
# Executive Summary
This document outlines our strategic initiatives for Q1 2026.
## Key Objectives
- Increase market share by 15%
- Launch new product line
- Expand to 3 new markets
## Timeline
Implementation begins February 1st, 2026.
`,
metadata: {
title: 'Q1 Strategic Plan',
subtitle: 'Confidential',
author: 'Strategy Team',
date: 'January 2026',
version: 'v1.0'
},
toc: true,
numberSections: true
});Generate a Business Memo
import { generateMemo } from 'ai-pdf-builder';
const memo = await generateMemo(
`
# Executive Summary
Key findings from our market analysis indicate strong growth potential.
## Recommendations
1. Accelerate product development
2. Increase marketing budget by 20%
3. Hire 5 additional engineers
`,
{
title: 'Product Whitepaper',
subtitle: 'Intelligence Infrastructure for Financial Markets',
author: 'John Smith',
date: 'January 2026'
}
);Generate a Legal Agreement
import { generateAgreement } from 'ai-pdf-builder';
const agreement = await generateAgreement(
`
# Advisor Agreement
This Advisor Agreement is entered into as of the Effective Date.
## 1. Services
The Advisor agrees to provide strategic guidance and introductions to potential investors.
## 2. Compensation
In consideration of the Services, the Company shall pay the Advisor:
- 8% of cash raised through Advisor's introductions
- 0.25% equity per $250,000 raised, up to 1% maximum
## 3. Term
This Agreement shall remain in effect for 12 months from the Effective Date.
`,
{
title: 'Capital Introduction Agreement',
subtitle: 'Acme Corp',
date: 'January 15, 2026'
}
);Generate a Term Sheet
import { generateTermsheet } from 'ai-pdf-builder';
const termsheet = await generateTermsheet(
`
# Series Seed Term Sheet
## Investment Amount
$2,000,000 (Two Million Dollars)
## Pre-Money Valuation
$8,000,000
## Security Type
Series Seed Preferred Stock
## Investors
Lead Investor: TBD
`,
{
title: 'Series Seed',
company: 'Acme Corp',
doctype: 'Term Sheet',
date: 'January 2026'
}
);Generate a Whitepaper
import { generateWhitepaper } from 'ai-pdf-builder';
const whitepaper = await generateWhitepaper(
`
# Abstract
This paper presents a novel approach to financial market intelligence.
# Introduction
Financial markets generate vast amounts of data...
# Technical Architecture
Our system consists of three main components...
# Conclusion
We have demonstrated a scalable solution for...
`,
{
title: 'Product Whitepaper',
subtitle: 'A Canonical Asset Resolution System',
author: 'Research Team',
version: 'v1.0',
date: 'January 2026'
}
);Custom Colors
import { generatePDF } from 'ai-pdf-builder';
const result = await generatePDF({
content: '# Branded Document\n\nWith custom colors!',
metadata: { title: 'Custom Branded PDF' },
customColors: {
primary: '#3B82F6', // Blue
secondary: '#6B7280', // Gray
accent: '#111827' // Dark
}
});Save to File
import { generatePDF } from 'ai-pdf-builder';
const result = await generatePDF({
content: '# My Document',
metadata: { title: 'Saved PDF' },
outputPath: './output/my-document.pdf'
});
if (result.success) {
console.log(`PDF saved to: ${result.path}`);
}Custom Templates
import { generatePDF, registerTemplate } from 'ai-pdf-builder';
// Register a custom template
registerTemplate({
name: 'company-branded',
path: './templates/company.latex',
description: 'Company branded template with logo',
supportedDocTypes: ['memo', 'whitepaper', 'report']
});
// Use the custom template
const result = await generatePDF({
content: '# Company Report',
metadata: { title: 'Annual Report' },
template: 'company-branded'
});List Available Templates
import { listTemplates } from 'ai-pdf-builder';
const templates = listTemplates();
templates.forEach(t => {
console.log(`${t.name}: ${t.description}`);
console.log(` Supports: ${t.supportedDocTypes.join(', ')}`);
});Check System Requirements
import { checkSystem } from 'ai-pdf-builder';
const status = checkSystem();
if (status.ready) {
console.log('System ready:', status.message);
} else {
console.error('Missing dependencies:', status.message);
if (!status.pandoc.available) {
console.error('Pandoc:', status.pandoc.error);
}
if (!status.latex.available) {
console.error('LaTeX:', status.latex.error);
}
}Integration with Next.js
API Route Example
// app/api/generate-pdf/route.ts
import { generatePDF } from 'ai-pdf-builder';
import { NextResponse } from 'next/server';
export async function POST(request: Request) {
const { content, title, type } = await request.json();
const result = await generatePDF({
content,
metadata: { title },
template: type === 'memo' ? 'memo' : 'default'
});
if (!result.success) {
return NextResponse.json({ error: result.error }, { status: 500 });
}
return new NextResponse(result.buffer, {
headers: {
'Content-Type': 'application/pdf',
'Content-Disposition': `attachment; filename="${title}.pdf"`
}
});
}Server Action Example
// app/actions/pdf.ts
'use server';
import { generateMemo } from 'ai-pdf-builder';
export async function createMemo(content: string, title: string) {
const result = await generateMemo(content, { title });
if (!result.success) {
throw new Error(result.error);
}
return result.buffer?.toString('base64');
}API Reference
CLI Commands
ai - AI Document Generation
npx ai-pdf-builder ai <prompt> [options]| Option | Alias | Description | Default |
|--------|-------|-------------|---------|
| --output | -o | Output file path | output.pdf |
| --template | -t | Template: memo, agreement, termsheet, whitepaper | Auto-detected |
| --company | -c | Load company context from company.json | false |
| --model | | Claude model | claude-sonnet-4-20250514 |
| --verbose | -v | Show progress | false |
generate - Markdown to PDF
npx ai-pdf-builder generate <input.md> [options]| Option | Alias | Description | Default |
|--------|-------|-------------|---------|
| --output | -o | Output file path | <input>.pdf |
| --template | -t | Template name | default |
| --title | | Document title | Filename |
| --author | | Document author | |
| --toc | | Include table of contents | true |
check - System Check
npx ai-pdf-builder checkVerifies Pandoc and LaTeX are properly installed.
generatePDF(options: PDFOptions): Promise
Main function to generate a PDF from Markdown content.
PDFOptions
| Property | Type | Required | Description |
|----------|------|----------|-------------|
| content | string | Yes | Markdown content to convert |
| metadata | DocumentMetadata | No | Document metadata (title, author, etc.) |
| template | string | No | Template name or path (default: 'default') |
| customColors | ColorConfig | No | Custom color configuration |
| outputPath | string | No | Save PDF to this path instead of returning buffer |
| toc | boolean | No | Include table of contents (default: true) |
| tocDepth | number | No | Depth of TOC (1-3, default: 2) |
| numberSections | boolean | No | Number sections (default: true) |
| fontSize | number | No | Font size in points (default: 11) |
| margin | string | No | Page margins (default: '1in') |
| paperSize | 'letter' \| 'a4' | No | Paper size (default: 'letter') |
| timeout | number | No | Timeout in ms (default: 60000) |
PDFResult
| Property | Type | Description |
|----------|------|-------------|
| success | boolean | Whether generation succeeded |
| buffer | Buffer | Generated PDF (if outputPath not specified) |
| path | string | Path to saved PDF (if outputPath specified) |
| error | string | Error message if failed |
| pageCount | number | Estimated page count |
| fileSize | number | File size in bytes |
| generationTime | number | Generation time in ms |
generateWithAI(options: AIGenerationOptions): Promise
Generate a PDF using AI to create the content.
AIGenerationOptions
| Property | Type | Required | Description |
|----------|------|----------|-------------|
| prompt | string | Yes | Description of what document to generate |
| template | string | No | Template to use (auto-detected if not specified) |
| metadata | DocumentMetadata | No | Override document metadata |
| companyContext | CompanyContext | No | Company details for context |
| model | string | No | Claude model (default: claude-sonnet-4-20250514) |
Example
import { generateWithAI } from 'ai-pdf-builder';
const result = await generateWithAI({
prompt: "Write an executive summary about our AI product launch",
template: "memo",
companyContext: {
name: "TechCorp",
industry: "AI/ML Software"
}
});Preset Functions
All preset functions have the signature:
function preset(
content: string,
metadata: DocumentMetadata,
options?: Partial<PDFOptions>
): Promise<PDFResult>Available presets:
generateMemo- Business memosgenerateAgreement- Legal agreementsgenerateTermsheet- Investment term sheetsgenerateWhitepaper- Technical whitepapersgenerateReport- Business reportsgenerateProposal- ProposalsgenerateCapitalIntroAgreement- Fundraising agreementsgenerateSAFE- SAFE documentsgenerateNDA- Non-disclosure agreements
Template Functions
getTemplate(name: string): string | null- Get template contentlistTemplates(): TemplateConfig[]- List all templatesregisterTemplate(config: TemplateConfig): void- Register custom templatehasTemplate(name: string): boolean- Check if template exists
Utility Functions
checkSystem(): SystemCheck- Check Pandoc/LaTeX availabilitycheckPandoc(): PandocCheck- Check Pandoc installationcheckLaTeX(): LaTeXCheck- Check LaTeX installationsanitizeContent(content: string): string- Sanitize for LaTeX safety
Built-in Templates
| Template | Description | Best For |
|----------|-------------|----------|
| default | Clean, professional styling | Whitepapers, reports |
| memo | Compact business memo | Executive summaries |
| agreement | Formal legal document | Contracts, agreements |
| termsheet | Premium dark + gold finance | Term sheets, investment docs |
Troubleshooting
"Pandoc not found"
Install Pandoc:
- macOS:
brew install pandoc - Ubuntu:
sudo apt-get install pandoc - Windows: Download from pandoc.org
"pdflatex not found"
Install LaTeX:
- macOS:
brew install --cask basictex - Ubuntu:
sudo apt-get install texlive-latex-base texlive-latex-extra - Windows: Install MiKTeX
Missing LaTeX packages
sudo tlmgr install <package-name>Common packages needed:
sudo tlmgr install fancyhdr titlesec enumitem xcolor booktabs longtable geometry hyperrefTimeout errors
Increase the timeout for large documents:
const result = await generatePDF({
content: longContent,
timeout: 120000 // 2 minutes
});Error Handling
Proper error handling is crucial for production applications.
Basic Error Handling
import { generatePDF } from 'ai-pdf-builder';
try {
const result = await generatePDF({
content: markdownContent,
metadata: { title: 'My Document' }
});
if (!result.success) {
console.error('PDF generation failed:', result.error);
// Handle specific errors
if (result.error?.includes('Pandoc')) {
console.error('Pandoc is not installed. Please install it first.');
// Guide user to installation instructions
} else if (result.error?.includes('pdflatex')) {
console.error('LaTeX is not installed. Please install TeX Live or MiKTeX.');
} else if (result.error?.includes('timeout')) {
console.error('Generation timed out. Try increasing the timeout option.');
}
return;
}
// Success - use result.buffer or result.path
console.log(`PDF generated successfully: ${result.fileSize} bytes`);
} catch (error) {
console.error('Unexpected error:', error);
// Handle system-level errors
}Retry Logic
async function generateWithRetry(
options: PDFOptions,
maxRetries: number = 3
): Promise<PDFResult> {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
const result = await generatePDF(options);
if (result.success) {
return result;
}
console.warn(`Attempt ${attempt}/${maxRetries} failed:`, result.error);
// Wait before retry (exponential backoff)
if (attempt < maxRetries) {
await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
}
}
throw new Error(`PDF generation failed after ${maxRetries} attempts`);
}Error Handling in Express
app.post('/api/pdf', async (req, res) => {
try {
const { content, title } = req.body;
const result = await generatePDF({
content,
metadata: { title },
timeout: 30000
});
if (!result.success) {
return res.status(500).json({
error: 'PDF generation failed',
details: result.error
});
}
res.setHeader('Content-Type', 'application/pdf');
res.setHeader('Content-Disposition', `attachment; filename="${title}.pdf"`);
res.send(result.buffer);
} catch (error) {
console.error('PDF generation error:', error);
res.status(500).json({ error: 'Internal server error' });
}
});TypeScript Best Practices
Get the most out of TypeScript's type system for safer code.
Fully Typed Configuration
import {
generatePDF,
PDFOptions,
PDFResult,
DocumentMetadata,
ColorConfig,
TemplateConfig
} from 'ai-pdf-builder';
// Type-safe metadata
const metadata: DocumentMetadata = {
title: 'Annual Report',
author: 'Jane Doe',
date: new Date().toLocaleDateString('en-US'),
version: 'v2.0',
subtitle: 'Financial Year 2025'
};
// Type-safe color configuration
const colors: ColorConfig = {
primary: '59,130,246', // RGB format
secondary: '107,114,128',
accent: '17,24,39'
};
// Complete options with type checking
const options: PDFOptions = {
content: markdownContent,
metadata,
customColors: colors,
template: 'default',
toc: true,
tocDepth: 2,
numberSections: true,
fontSize: 11,
margin: '1in',
paperSize: 'letter',
timeout: 60000
};
const result: PDFResult = await generatePDF(options);
// Type-safe result handling
if (result.success && result.buffer) {
const size: number = result.fileSize || 0;
const pages: number = result.pageCount || 0;
console.log(`Generated ${pages} pages (${size} bytes)`);
}Custom Type Guards
import { PDFResult } from 'ai-pdf-builder';
function isSuccessfulResult(result: PDFResult): result is PDFResult & {
success: true;
buffer: Buffer
} {
return result.success && !!result.buffer;
}
// Use the type guard
const result = await generatePDF(options);
if (isSuccessfulResult(result)) {
// TypeScript knows result.buffer is defined here
saveToFile(result.buffer);
}Extending Types
import { DocumentMetadata } from 'ai-pdf-builder';
// Extend with custom metadata
interface CustomMetadata extends DocumentMetadata {
department?: string;
classification?: 'public' | 'internal' | 'confidential';
reviewers?: string[];
}
const metadata: CustomMetadata = {
title: 'Security Report',
author: 'Security Team',
date: '2026-01-22',
department: 'IT Security',
classification: 'confidential',
reviewers: ['Alice', 'Bob']
};Advanced Topics
Batch Processing
Generate multiple PDFs concurrently:
import { generatePDF } from 'ai-pdf-builder';
import pLimit from 'p-limit';
async function generateBatch(documents: Array<{ content: string; title: string }>) {
// Limit concurrent operations to avoid overwhelming the system
const limit = pLimit(3);
const tasks = documents.map(doc =>
limit(() => generatePDF({
content: doc.content,
metadata: { title: doc.title }
}))
);
const results = await Promise.all(tasks);
// Process results
const successful = results.filter(r => r.success);
const failed = results.filter(r => !r.success);
console.log(`Generated ${successful.length}/${results.length} PDFs`);
return { successful, failed };
}Performance Optimization
Tips for large documents:
// 1. Increase timeout for large documents
const result = await generatePDF({
content: largeMarkdownContent,
timeout: 180000 // 3 minutes
});
// 2. Disable TOC for faster generation
const result = await generatePDF({
content,
toc: false, // Skip table of contents
numberSections: false
});
// 3. Use simpler templates
const result = await generatePDF({
content,
template: 'default' // Simpler than termsheet template
});
// 4. Process in chunks for very large documents
async function generateLargeDocument(sections: string[]) {
const pdfs = await Promise.all(
sections.map(section => generatePDF({
content: section,
toc: false
}))
);
// Merge PDFs using a library like pdf-lib
}Memory Management
For high-volume operations:
import { generatePDF } from 'ai-pdf-builder';
// Monitor memory usage
function logMemoryUsage() {
const used = process.memoryUsage();
console.log({
rss: `${Math.round(used.rss / 1024 / 1024)}MB`,
heapUsed: `${Math.round(used.heapUsed / 1024 / 1024)}MB`
});
}
// Process in batches to avoid memory issues
async function processLargeQueue(queue: any[], batchSize = 10) {
for (let i = 0; i < queue.length; i += batchSize) {
const batch = queue.slice(i, i + batchSize);
await Promise.all(batch.map(item => generatePDF(item)));
// Allow garbage collection between batches
await new Promise(resolve => setImmediate(resolve));
logMemoryUsage();
}
}Custom Template Creation
Create your own LaTeX templates:
import { registerTemplate, generatePDF } from 'ai-pdf-builder';
import * as path from 'path';
// Register a custom template
registerTemplate({
name: 'company-branded',
path: path.join(__dirname, 'templates', 'company.latex'),
description: 'Company branded template with logo',
supportedDocTypes: ['memo', 'whitepaper', 'report']
});
// Use the custom template
const result = await generatePDF({
content: markdownContent,
template: 'company-branded',
customColors: {
primary: '0,102,204', // Company blue
secondary: '128,128,128'
}
});See TEMPLATE_GUIDE.md for a complete guide to creating custom LaTeX templates.
Production Deployment
Docker Deployment
Dockerfile:
FROM pandoc/latex:latest
# Install Node.js
RUN apk add --no-cache nodejs npm
# Set working directory
WORKDIR /app
# Copy package files
COPY package*.json ./
RUN npm ci --only=production
# Copy application
COPY . .
# Install required LaTeX packages
RUN tlmgr update --self && \
tlmgr install \
collection-fontsrecommended \
fancyhdr \
titlesec \
enumitem \
xcolor \
booktabs \
longtable \
geometry \
hyperref \
setspace \
array \
multirow \
listings
EXPOSE 3000
CMD ["node", "server.js"]docker-compose.yml:
version: '3.8'
services:
pdf-generator:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- MAX_CONCURRENT_PDFS=3
volumes:
- pdf-cache:/app/cache
mem_limit: 2g
mem_reservation: 1g
volumes:
pdf-cache:Next.js Production Configuration
// next.config.js
module.exports = {
experimental: {
serverComponentsExternalPackages: ['ai-pdf-builder']
},
// Increase API route timeout for PDF generation
api: {
responseLimit: '8mb'
}
};
// app/api/pdf/route.ts
import { generatePDF } from 'ai-pdf-builder';
import { NextResponse } from 'next/server';
export const maxDuration = 60; // 60 seconds timeout
export async function POST(request: Request) {
const { content, title } = await request.json();
const result = await generatePDF({
content,
metadata: { title },
timeout: 50000 // Leave buffer before Next.js timeout
});
if (!result.success) {
return NextResponse.json({ error: result.error }, { status: 500 });
}
return new NextResponse(result.buffer, {
headers: {
'Content-Type': 'application/pdf',
'Content-Disposition': `attachment; filename="${title}.pdf"`,
'Cache-Control': 'no-store'
}
});
}Serverless Considerations
AWS Lambda:
// Lambda function with custom runtime
// NOTE: Lambda has a 512MB /tmp limit and 15min timeout
import { generatePDF } from 'ai-pdf-builder';
export const handler = async (event) => {
// Use /tmp for working directory
const result = await generatePDF({
content: event.content,
metadata: event.metadata,
workDir: '/tmp/pdf-work',
timeout: 840000 // 14 minutes (leave buffer)
});
if (result.success) {
// Upload to S3 instead of returning (size limits)
await uploadToS3(result.buffer, event.key);
return { statusCode: 200, body: JSON.stringify({ url: s3Url }) };
}
return { statusCode: 500, body: JSON.stringify({ error: result.error }) };
};Note: For serverless, consider using the container approach or a dedicated PDF generation service due to Pandoc/LaTeX size requirements.
Error Monitoring
Sentry Integration:
import * as Sentry from '@sentry/node';
import { generatePDF } from 'ai-pdf-builder';
Sentry.init({ dsn: process.env.SENTRY_DSN });
async function generateWithMonitoring(options) {
const transaction = Sentry.startTransaction({
op: 'pdf.generate',
name: 'Generate PDF'
});
try {
const result = await generatePDF(options);
if (!result.success) {
Sentry.captureMessage('PDF generation failed', {
level: 'error',
extra: { error: result.error, options }
});
}
transaction.setStatus('ok');
return result;
} catch (error) {
Sentry.captureException(error);
transaction.setStatus('internal_error');
throw error;
} finally {
transaction.finish();
}
}FAQ
How does AI generation work?
The ai command sends your prompt to Claude (Anthropic's AI), which generates professional Markdown content based on your description. This content is then converted to PDF using Pandoc and LaTeX.
What makes it smart:
- Automatically detects document type from your prompt
- Structures content appropriately (headers, sections, formatting)
- Uses professional language and business conventions
- With
--company, includes your company details naturally
What's the difference between AI and manual generation?
| Aspect | AI Generation | Manual (Markdown) | |--------|--------------|-------------------| | Input | Natural language prompt | Structured Markdown | | Control | AI decides structure | You control everything | | Speed | Fastest for drafts | Better for precise docs | | Best for | First drafts, ideas, quick docs | Final versions, exact specs |
Pro tip: Use AI to generate a first draft, then export the Markdown for manual refinement.
Why is my PDF generation slow?
PDF generation involves multiple steps (Markdown parsing, LaTeX compilation, font rendering). Typical generation times:
- Simple document (1-5 pages): 1-3 seconds
- Medium document (10-20 pages): 3-8 seconds
- Large document (50+ pages): 10-30 seconds
To improve performance:
- Disable TOC if not needed (
toc: false) - Use simpler templates (
template: 'default') - Process documents concurrently for batch operations
- Cache generated PDFs when possible
Can I use this in a serverless environment?
Yes, but with caveats:
- Docker-based serverless (AWS Fargate, Cloud Run): ✅ Recommended
- Traditional Lambda/Functions: ⚠️ Challenging due to Pandoc/LaTeX dependencies (~300MB)
For traditional serverless, consider:
- Using a custom Lambda layer with Pandoc/LaTeX
- Calling a dedicated PDF generation service
- Using AWS Lambda Container Images
How do I debug LaTeX errors?
// Enable detailed error logging
const result = await generatePDF({
content: markdownContent,
metadata: { title: 'Debug Test' }
});
if (!result.success) {
console.error('Full error:', result.error);
// LaTeX errors typically mention line numbers and commands
// Example: "LaTeX Error: Environment Shaded undefined"
}Common LaTeX errors:
- "pdflatex not found": Install LaTeX (see Prerequisites)
- "Unicode character not set up": Use ASCII alternatives or configure unicode support
- "Environment undefined": Missing LaTeX package
What Markdown features are supported?
Supported (via Pandoc):
- ✅ Headers (H1-H6)
- ✅ Lists (ordered, unordered, nested)
- ✅ Bold, italic, code
- ✅ Links and URLs
- ✅ Tables (simple and grid)
- ✅ Code blocks with syntax highlighting
- ✅ Blockquotes
- ✅ Horizontal rules
- ✅ Images (if file paths are accessible)
Limited support:
- ⚠️ HTML (basic tags only)
- ⚠️ Complex tables (may need LaTeX syntax)
- ⚠️ Emojis (depends on LaTeX font support)
Not supported:
- ❌ GitHub-flavored Markdown task lists
- ❌ Mermaid diagrams (consider rendering to image first)
How do I add images to my PDFs?
const content = `
# Document with Images

Regular text here.
{ width=80% }
`;
const result = await generatePDF({
content,
metadata: { title: 'Document with Images' }
});Requirements:
- Image paths must be accessible from where the code runs
- Supported formats: PNG, JPG, PDF
- Use relative or absolute paths
- Control size with Pandoc syntax:
{ width=50% }or{ height=3in }
Can I generate PDFs from HTML?
Yes, convert HTML to Markdown first or use Pandoc's HTML input:
import { generatePDF } from 'ai-pdf-builder';
import TurndownService from 'turndown';
// Convert HTML to Markdown
const turndown = new TurndownService();
const markdown = turndown.turndown(htmlContent);
const result = await generatePDF({
content: markdown,
metadata: { title: 'From HTML' }
});How do I handle concurrent requests?
Use a queue system to limit concurrent PDF generations:
import Queue from 'bull';
import { generatePDF } from 'ai-pdf-builder';
const pdfQueue = new Queue('pdf-generation', process.env.REDIS_URL);
// Limit to 3 concurrent jobs
pdfQueue.process(3, async (job) => {
return await generatePDF(job.data.options);
});
// Add jobs
app.post('/api/pdf', async (req, res) => {
const job = await pdfQueue.add({ options: req.body });
res.json({ jobId: job.id });
});Integrations
ai-pdf-builder is designed to work seamlessly with AI agents and automation platforms:
AI Agent Frameworks
| Framework | Integration | |-----------|-------------| | Clawdbot / Moltbot | Native support — generate PDFs from chat commands | | LangChain | Use as a tool in your agent chains | | AutoGPT | Add as a plugin for document generation | | CrewAI | Integrate as an agent capability | | Semantic Kernel | Use via function calling |
Messaging Platforms
Works with any bot framework that can execute Node.js:
- Telegram —
node-telegram-bot-api,telegraf - WhatsApp —
whatsapp-web.js,@whiskeysockets/baileys - Discord —
discord.js - Slack —
@slack/bolt - Signal —
signal-cli
Automation Tools
- n8n — Use the Execute Command or Code node
- Zapier — Via Code by Zapier or webhooks
- Make (Integromat) — HTTP module + hosted endpoint
- Pipedream — Native Node.js support
Example: LangChain Tool
import { Tool } from "langchain/tools";
import { generateWithAI } from "ai-pdf-builder";
const pdfTool = new Tool({
name: "generate_pdf",
description: "Generate a professional PDF document from a description",
func: async (prompt: string) => {
const result = await generateWithAI({ prompt });
if (result.success) {
// Save or return the PDF
return `PDF generated: ${result.fileSize} bytes`;
}
return `Error: ${result.error}`;
}
});Example: Telegram Bot
import TelegramBot from 'node-telegram-bot-api';
import { generateWithAI } from 'ai-pdf-builder';
const bot = new TelegramBot(process.env.BOT_TOKEN, { polling: true });
bot.onText(/\/pdf (.+)/, async (msg, match) => {
const chatId = msg.chat.id;
const prompt = match[1];
await bot.sendMessage(chatId, '📄 Generating your PDF...');
const result = await generateWithAI({ prompt });
if (result.success) {
await bot.sendDocument(chatId, result.buffer, {
filename: 'document.pdf'
});
}
});Author
Built by @NextXFrontier — Follow for AI tools, automation, and building in public.
License
MIT
Contributing
Contributions welcome! Please read our CONTRIBUTING.md guidelines before submitting PRs.
