PDF Export
Export your Fumadocs documentation pages as high-quality PDF files
Export your Fumadocs documentation pages as high-quality PDF files with automatic discovery and batch processing.
Features
Quick Start
Start Development Server
pnpm devWait for the server to be ready at http://localhost:3000
Export PDFs
bash pnpm export-pdf Exports all documentation pages to the pdfs/ directory.bash pnpm export-pdf:specific /docs /docs/getting-started Export only the specified pages.bash pnpm export-pdf:build Automated build and export (recommended for final PDFs).Find Your PDFs
PDFs are saved to the pdfs/ directory:
pdfs/
├── index.pdf
├── docs-getting-started.pdf
└── docs-features-pdf-export.pdfHow It Works
Print Styles
Special CSS in app/global.css hides navigation elements and optimizes for printing:
@media print {
#nd-docs-layout {
--fd-sidebar-width: 0px !important;
}
#nd-sidebar {
display: none;
}
pre,
img {
page-break-inside: avoid;
}
}Component Overrides
When NEXT_PUBLIC_PDF_EXPORT=true, interactive components render expanded:
const isPrinting = process.env.NEXT_PUBLIC_PDF_EXPORT === "true";
return {
Accordion: isPrinting ? PrintingAccordion : Accordion,
Tab: isPrinting ? PrintingTab : Tab,
};Export Script
The scripts/export-pdf.ts script uses Puppeteer to:
- Discover all documentation pages from
source.getPages() - Navigate to each page with headless Chrome
- Wait for content to load
- Generate PDF with custom settings
await page.pdf({
path: outputPath,
width: "950px",
printBackground: true,
margin: {
top: "20px",
right: "20px",
bottom: "20px",
left: "20px",
},
});Configuration
PDF Settings
Edit scripts/export-pdf.ts to customize PDF output:
await page.pdf({
path: outputPath,
width: "950px", // Page width
printBackground: true, // Include backgrounds
margin: {
// Page margins
top: "20px",
right: "20px",
bottom: "20px",
left: "20px",
},
});Concurrency Control
Adjust parallel exports to match your server capacity:
const CONCURRENCY = 3; // Export 3 pages at a timeEnvironment Variables
Set NEXT_PUBLIC_PDF_EXPORT=true to enable PDF-friendly rendering:
NEXT_PUBLIC_PDF_EXPORT=true pnpm buildAdvanced Usage
Custom Page Selection
Modify getAllDocUrls() to filter pages:
async function getAllDocUrls(): Promise<string[]> {
const pages = source.getPages();
return pages
.filter((page) => page.url.startsWith("/docs/api")) // Only API docs
.map((page) => page.url);
}Custom Viewport
Change rendering viewport for different display sizes:
await page.setViewport({
width: 1920, // Wider viewport
height: 1080,
});Add Headers/Footers
Puppeteer supports custom PDF headers and footers:
await page.pdf({
// ... other options
displayHeaderFooter: true,
headerTemplate: '<div style="font-size: 10px;">My Docs</div>',
footerTemplate: '<div style="font-size: 10px;">Page <span class="pageNumber"></span></div>',
});Troubleshooting
PDFs are blank
Increase Timeout
timeout: 60000; // 60 secondsCheck Server
curl http://localhost:3000/docsView Browser
Set headless: false in launch options to see what's happening.
Missing Content
NEXT_PUBLIC_PDF_EXPORT=true is set during build: bash NEXT_PUBLIC_PDF_EXPORT=true pnpm build Navigation Still Visible
- Clear
.nextcache:rm -rf .next - Rebuild with PDF export mode enabled
- Verify print styles in browser dev tools
Timeout Errors
- Reduce concurrency:
CONCURRENCY = 1 - Increase timeout values
- Check server resources
Best Practices
- Always use production build for final exports
- Test with single pages first before exporting all
- Monitor server resources during large exports
- Review PDFs before distribution
Scripts Reference
| Script | Description |
|---|---|
pnpm export-pdf | Export all pages (requires server running) |
pnpm export-pdf:specific <urls...> | Export specific pages |
pnpm export-pdf:build | Build and export (automated) |
Tips
- Export during off-peak hours for large sites
- Use
--no-sandboxflag if running in containers - Consider PDF file size when distributing
- Test exports on different content types
- Keep Puppeteer updated for best compatibility