Building a PDF generation service using Nextjs and React PDF
Introduction
PDF generation is a common requirement in expense management applications, but implementing it efficiently can be challenging. At Expense AI, we recently transformed our PDF generation system from a backend-heavy approach to a more maintainable, frontend-focused solution.
In this article, I’ll share our journey, the challenges we faced, and how we leveraged Next.js and React PDF to build a robust PDF generation service.
The Legacy System: What Wasn’t Working
Our initial PDF generation system relied on:
- Adonis.js edge template engine
- Tailwind CSS for styling
- Puppeteer for rendering
While functional, this setup presented several critical challenges:
- Slow Build Times: The Puppeteer’s large size caused deployment timeouts.
- Poor Developer Experience: Limited IDE support for Adonis.js edge templates.
- Performance Issues: Complex reports with images frequently timed out
The Solution: A Dedicated PDF Service
To address these pain points, we decided to create a separate PDF generation service using Next.js. This approach allowed us to:
- Leverage modern web development tools
- Improve development experience
- Enhance performance and reliability
Technical Implementation
We chose to combine react-pdf-tailwind
with react-pdf
to maintain compatibility with our existing Tailwind CSS templates. The implementation involved three key components:
UI Primitives
The UI Primitives implementation creates a bridge between Tailwind CSS and React PDF components. Here’s what’s happening:
Usage Example
In the example below, we register the font and then use the UI primitives to compose the PDF document.
API Integration
The API endpoint orchestrates the PDF generation and delivery process through a streamlined approach. It dynamically renders components based on response status, converting them into PDF streams for efficient delivery.
With proper content-type headers and cache control, the endpoint ensures reliable PDF delivery while maintaining unique file identification through timestamp-based naming. Here’s the implementation:
Architecture Overview
Our new system follows a clear sequence:
- The user initiates report generation with filter parameters
- The backend encrypts parameters and generates a secure URL
- The mobile app requests a PDF preview
- Report service fetches and processes data
- PDF is generated and delivered to the user
Results and Impact
Improvements
- Build time reduced from 20 minutes to 3 minutes
- Eliminated timeout issues
- Better system architecture and maintainability
Limitations and Considerations
- React-pdf has limited styling options e.g. grid layout is not supported.
- Limited HTML elements e.g. The table element isn’t supported so we implemented the table layout using flex-box.
This led to inconsistency/unexpected behavior in the report layout.
Technical Considerations
- React PDF compatibility required downgrading to Next.js 14
- Potential future migration to Express.js for better memory management depending on Next.js memory usage.
Conclusion
Our migration to this new PDF generation service brought substantial improvements to both development workflow and performance. However, before adopting React PDF for your projects, carefully evaluate whether its capabilities align with your needs. Consider factors such as:
- The complexity of your PDF layouts
- Your styling requirements (especially if you heavily rely on grid layouts or tables)
- Your team’s familiarity with React and Tailwind
- While React PDF worked well for our use case at Expense AI, other solutions like PDFKit, wkhtmltopdf, or Puppeteer might be more suitable depending on your specific requirements.
If you found this article helpful, I’d appreciate your claps and shares! 👏
Want to see this PDF generation service in action? Check out Expense AI — we’re helping businesses streamline their expense management with features like this and many more.
Feel free to connect with me on LinkedIn for more tech insights and discussions. Drop a comment below if you have any questions or experiences to share!
Additional Resources
React PDF — https://react-pdf.org/
React PDF Tailwind — https://www.npmjs.com/package/react-pdf-tailwind