Web Development Node.js ERP Systems

PDFKit for Invoices: Retail & Manufacturing Guide

Learn how to use PDFKit to generate professional, customized PDF invoices for ERP systems in retail and garment manufacturing with practical Node.js examples.

Sariful Islam

Sariful Islam

PDFKit for Invoices: Retail & Manufacturing Guide - Image | Sariful Islam

If you’ve ever built an ERP system for retail or garment manufacturing businesses, you know one truth: invoices matter. A lot.

They’re not just receipts. They’re a reflection of your business personality, a legal document, and often the last touchpoint with a customer. When I started building billing solutions at Zubizi Web Solutions, generating professional PDF invoices became one of our most critical challenges. After exploring various tools, we found our answer in PDFKit, a powerful Node.js library for PDF generation that transformed how we handle invoices.

In this post, I’ll share what I’ve learned about using PDFKit to create custom invoices for retail and garment manufacturing clients, complete with practical code examples and lessons from real projects.

The Invoice Generation Challenge

When we first started working with retail and garment manufacturing clients, we quickly realized that off-the-shelf invoice templates weren’t cutting it. Each business had unique needs: different branding, specific data fields, various tax structures, and most importantly, they wanted invoices that reflected their business personality.

The main challenge was producing professional, customized invoices that could adapt to each client’s requirements without compromising on quality or performance. We needed something flexible enough to handle complex layouts but simple enough to maintain and scale.

Why We Chose PDFKit

I’ll be honest, we tried a few different approaches before settling on PDFKit. We looked at headless browser solutions, template-based generators, and even third-party APIs. But PDFKit stood out for several reasons.

First, it offered the flexibility and ease of integration needed for dynamic invoice generation within our existing Node.js technology stack. Since our ERP systems were already built with Node.js, adding PDFKit didn’t require introducing a new language or framework. This kept our codebase consistent and our team productive.

Second, PDFKit gives you complete control over the PDF layout. You’re not constrained by templates or predefined structures. Want to add a company logo? Position text at exact coordinates? Draw custom tables? PDFKit handles it all through straightforward JavaScript code.

Third, the performance is solid. Once properly optimized, PDFKit can generate invoices quickly, even when you need to process multiple documents simultaneously.

A Real Project That Changed Everything

Let me share a specific example. We built a billing application for a mid-sized garment manufacturer in Kolkata. Before implementing PDFKit, their invoicing process was manual and inconsistent. Sales staff would fill out Excel templates, which often resulted in formatting errors and unprofessional-looking documents.

With PDFKit, we automated the entire process. The system would pull order data, calculate totals including GST, and generate clean, branded invoices instantly. The invoices featured their company logo, proper alignment, and a consistent layout that looked professional whether printed or viewed digitally.

The impact was immediate. Their billing cycle shortened from days to hours, and customer complaints about invoice errors dropped significantly. This project taught us that good invoice generation isn’t just about creating PDFs, it’s about building confidence in your business operations.

Building Your First Invoice with PDFKit

Let’s get practical. Here’s a complete example of how to generate a professional invoice using PDFKit in Node.js. This code creates a retail invoice with all essential elements: company header, item table, totals, and proper formatting.

const PDFDocument = require('pdfkit');
const fs = require('fs');

// Sample invoice data
const invoiceData = {
  invoiceNumber: 'INV-2025-001',
  date: '25-Nov-2025',
  customerName: 'Retail Store ABC',
  customerAddress: '123 Market Street, Kolkata, WB 700001',
  items: [
    { name: 'Cotton T-Shirt (Large)', quantity: 50, rate: 250, amount: 12500 },
    { name: 'Denim Jeans (32)', quantity: 30, rate: 800, amount: 24000 },
    { name: 'Summer Dress (M)', quantity: 25, rate: 450, amount: 11250 }
  ],
  subtotal: 47750,
  gst: 8595, // 18% GST
  total: 56345
};

function generateInvoice(data, filename) {
  // Create a new PDF document
  const doc = new PDFDocument({ margin: 50 });

  // Pipe the PDF to a file
  doc.pipe(fs.createWriteStream(filename));

  // Add company header
  doc.fontSize(20)
     .text('Zubizi Web Solutions', 50, 50)
     .fontSize(10)
     .text('123 Tech Park, Kolkata, WB 700091', 50, 75)
     .text('GST: 19XXXXX1234X1XX | Phone: +91-XXXXXXXXXX', 50, 90);

  // Add invoice title and details
  doc.fontSize(16)
     .text('INVOICE', 50, 130, { underline: true });

  doc.fontSize(10)
     .text(`Invoice No: ${data.invoiceNumber}`, 50, 160)
     .text(`Date: ${data.date}`, 50, 175);

  // Customer details
  doc.fontSize(12)
     .text('Bill To:', 50, 210)
     .fontSize(10)
     .text(data.customerName, 50, 230)
     .text(data.customerAddress, 50, 245);

  // Create item table
  const tableTop = 290;
  const itemCodeX = 50;
  const quantityX = 250;
  const rateX = 320;
  const amountX = 420;

  // Table header
  doc.fontSize(10)
     .text('Item Description', itemCodeX, tableTop, { bold: true })
     .text('Qty', quantityX, tableTop)
     .text('Rate', rateX, tableTop)
     .text('Amount', amountX, tableTop);

  // Draw line under header
  doc.moveTo(50, tableTop + 15)
     .lineTo(550, tableTop + 15)
     .stroke();

  // Add items
  let y = tableTop + 25;
  data.items.forEach((item, index) => {
    doc.text(item.name, itemCodeX, y)
       .text(item.quantity.toString(), quantityX, y)
       .text(`₹${item.rate}`, rateX, y)
       .text(`₹${item.amount}`, amountX, y);
    y += 25;
  });

  // Draw line before totals
  doc.moveTo(50, y + 5)
     .lineTo(550, y + 5)
     .stroke();

  // Add totals
  y += 20;
  doc.text('Subtotal:', 350, y)
     .text(`₹${data.subtotal}`, amountX, y);

  y += 20;
  doc.text('GST (18%):', 350, y)
     .text(`₹${data.gst}`, amountX, y);

  y += 20;
  doc.fontSize(12)
     .text('Total Amount:', 350, y, { bold: true })
     .text(`₹${data.total}`, amountX, y);

  // Add footer
  doc.fontSize(8)
     .text('Thank you for your business!', 50, 700, { align: 'center' })
     .text('This is a computer-generated invoice', 50, 715, { align: 'center' });

  // Finalize the PDF
  doc.end();

  console.log(`Invoice generated: ${filename}`);
}

// Generate the invoice
generateInvoice(invoiceData, 'invoice-INV-2025-001.pdf');

This code creates a professional invoice with all the essential elements. The layout is clean, the formatting is consistent, and it includes GST calculations, which is crucial for Indian businesses.

Technical Obstacles and How We Overcame Them

When we first started using PDFKit, everything wasn’t smooth sailing. We faced performance bottlenecks, especially when clients needed to generate hundreds of invoices at month-end.

The biggest issue was with large data sets. When generating bulk invoices, our server would slow down significantly. We addressed this by optimizing data fetching - instead of loading all customer and product details for each invoice separately, we batched the database queries and cached frequently accessed data like company information and tax rates.

Another challenge was font handling. Different clients wanted different fonts for branding. We learned to embed custom fonts properly and maintain a library of commonly used fonts to avoid loading them repeatedly.

Ensuring Consistent Formatting

One lesson I learned the hard way: PDF rendering can vary slightly across different PDF viewers and printers. We standardize fonts to keep formatting stable regardless of platform or printer settings.

Here are the practices we follow:

  1. Use standard fonts: Stick to fonts like Helvetica, Times, or embed custom fonts properly
  2. Define exact positions: Use absolute positioning for critical elements like logos and totals
  3. Test across devices: Always test PDFs on different screens, printers, and PDF readers
  4. Set proper page margins: Maintain consistent margins (we use 50 points) to ensure content doesn’t get cut off
  5. Use points, not pixels: PDFKit works with points (1/72 inch), which translates better to print

Customer Feedback That Validated Our Approach

The best part of implementing PDFKit has been the customer response. Clients appreciate the clear layout and accurate data representation. One garment manufacturer told us that billing disputes dropped by 60% after we implemented the new invoice system. The clarity and professionalism of the PDFs gave their customers confidence in the charges.

Customers also love the speed. In our billing application, invoices generate in under 2 seconds, even for complex multi-item orders. This instant gratification makes a real difference in customer-facing scenarios.

A Mistake That Taught Us Better

I’ll share an embarrassing moment. Early on, we had an invoice system that worked perfectly in testing. We deployed it, and within a week, we got calls from confused customers. The problem? Incorrect currency formatting.

We were using JavaScript’s default number formatting, which sometimes added extra decimal places or dropped them entirely. An invoice showing “₹1500.5999999999999” instead of “₹1,500.50” looked unprofessional and caused confusion about the actual amount due.

This prompted us to implement stricter validation before rendering PDFs. Now we use proper number formatting functions, validate all financial calculations twice, and have a review checklist for any invoice template changes. That one mistake made our invoice generation much more robust.

Performance Tips for Bulk Invoice Generation

When you need to generate multiple invoices simultaneously, performance becomes critical. Here are the optimization strategies that worked for us:

Optimize Data Fetching

When fetching the data, try to reduce the time. Instead of querying the database for each invoice individually, batch your queries. Load all customer data in one go, all product details in another, and then combine them in memory. This reduces database round trips significantly.

Image Optimization

If you are using images like logos or product photos, try to minify the image and convert it into lower resolution to make it faster. We typically use 150 DPI for logos in invoices. It looks crisp on screen and prints well without bloating the PDF file size.

A 2MB logo can slow down PDF generation noticeably. We resize logos to 200x80 pixels and compress them to under 50KB. The difference in generation speed is dramatic.

Reuse PDF Document Settings

If generating multiple invoices in a loop, consider reusing certain objects like font registrations and image buffers. PDFKit allows you to register fonts once and use them across multiple documents.

Stream to Cloud Storage

Instead of writing PDFs to disk first, stream them directly to cloud storage or send them as HTTP responses. This eliminates the file I/O overhead and speeds up the process.

How PDFKit Transformed Our ERP Systems

Mastering PDFKit enabled us to deliver polished, customizable invoices quickly, improving client satisfaction and operational efficiency across our ERP systems. It’s not just about generating PDFs anymore. It’s about giving our clients confidence in their business processes.

For retail businesses, fast and accurate invoicing means faster payments and better cash flow. For garment manufacturers dealing with complex orders involving multiple SKUs, sizes, and colors, clear invoices reduce errors and returns.

PDFKit became a cornerstone of our ERP solutions. We now use it not just for invoices but for delivery challans, purchase orders, quotations, and financial reports. The flexibility it offers allows us to adapt to each client’s unique requirements without rebuilding the entire system.

Getting Started with PDFKit

If you’re considering PDFKit for your project, here’s my advice: start simple. Build a basic invoice first, get comfortable with positioning and formatting, then gradually add complexity.

Install PDFKit using npm:

npm install pdfkit

Start with the example I shared above, modify it for your needs, and test thoroughly. The PDFKit documentation is excellent, and the community is helpful if you get stuck.

Remember that PDF generation is as much about design as it is about code. Spend time making your invoices visually appealing. Good typography, proper spacing, and clear hierarchy make invoices easier to read and more professional.

Final Thoughts

Building robust invoice generation with PDFKit has been one of the most satisfying technical challenges I’ve tackled at Zubizi. It’s a perfect example of how choosing the right tool and taking time to master it can create real value for your clients.

Whether you’re building ERP systems, billing applications, or any software that needs professional PDF output, PDFKit is worth exploring. It’s flexible, performant, and gives you complete control over your document layout.

If you’re working on similar challenges or have questions about implementing PDFKit in your projects, I’d love to hear from you. Feel free to reach out through the contact page, and let’s discuss how we can make invoice generation better for everyone.

Happy coding, and may your invoices always be pixel-perfect!