reportgen
Back to all posts

Migrating from Legacy PDF Tools: A Step-by-Step Guide to reportgen.io 🚀

March 18, 2025

If you're reading this, you're probably fed up with your current PDF solution.

Maybe it's the random failures. The hidden costs. The terrible documentation. Or the fact that it takes three business days to get support to respond to a critical issue.

You've decided it's time to migrate. Smart move.

But migration can feel daunting. How do you switch PDF providers without breaking production? How do you replicate your existing templates? What about that custom styling you fought so hard to get working?

This guide will show you exactly how to migrate to reportgen.io - step by step, with zero drama.


Why Migrate to reportgen.io?

Before we dive in, let's be clear about what you're gaining:

No file size limits - Generate 189MB PDFs without breaking a sweat ✅ Transparent pricing - $0.0025 per PDF, no hidden fees ✅ Multiple templating engines - EJS, Handlebars, GoTempl, or raw HTML ✅ 99.999% reliability - Built on battle-tested infrastructure ✅ Developer-first API - Clean, predictable, well-documented


Phase 1: Audit Your Current Setup (30 Minutes)

Before touching any code, you need to understand what you're working with.

Step 1: Document Your Current PDF Generation Flow

Answer these questions:

  1. Where are PDFs generated? (Background job? API endpoint? Cron task?)
  2. What triggers generation? (User action? Webhook? Scheduled event?)
  3. What templating engine do you use? (Mustache? Jinja? Embedded HTML?)
  4. Where are PDFs stored? (S3? Database? Local filesystem?)
  5. How many PDFs per month? (Helps estimate costs)

Step 2: Identify Your Templates

List every PDF template you're currently using:

  • Invoice template
  • Monthly report template
  • User dashboard export
  • Custom analytics report
  • etc.

Pro tip: Start with your most critical, highest-volume template for the initial migration. Get that working perfectly, then migrate the rest.


Phase 2: Set Up reportgen.io (15 Minutes)

Step 1: Create Your Account

  1. Go to reportgen.io/sign-up
  2. Sign up (no credit card required)
  3. Navigate to Access Keys
  4. Generate your API key

Step 2: Add Your API Key to Your Environment

# .env file
REPORTGEN_API_KEY=your_api_key_here

Phase 3: Convert Your First Template (1-2 Hours)

Let's migrate your most important template first.

Step 1: Choose Your Templating Engine

reportgen.io supports:

  • EJS - JavaScript-based, great for complex logic
  • Handlebars - Logic-less, simple and clean
  • GoTempl - Go templates for Go-based apps
  • Raw HTML - Pre-rendered HTML

Migration tip: If you're coming from Mustache/Liquid/Jinja, Handlebars is your easiest path. The syntax is nearly identical.

Step 2: Convert Your Template

Here's an example migration from a legacy tool to Handlebars:

Before (Legacy Tool):

<h1>Invoice #{{ invoice.id }}</h1>
<p>Customer: {{ customer.name }}</p>
<p>Total: ${{ invoice.total }}</p>

After (reportgen.io with Handlebars):

<h1>Invoice #{{invoice.id}}</h1>
<p>Customer: {{customer.name}}</p>
<p>Total: ${{invoice.total}}</p>

Yep, that's it. Zero changes needed for basic templates.

Step 3: Test Your Template

Create a test script:

import fetch from 'node-fetch';
import fs from 'fs';
 
const apiKey = process.env.REPORTGEN_API_KEY;
 
const testData = {
  invoice: { id: '12345', total: 1500 },
  customer: { name: 'Acme Corp' }
};
 
const htmlTemplate = `
<h1>Invoice #{{invoice.id}}</h1>
<p>Customer: {{customer.name}}</p>
<p>Total: ${{invoice.total}}</p>
`;
 
const response = await fetch('https://reportgen.io/api/v1/generate-pdf-sync', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-API-Key': apiKey
  },
  body: JSON.stringify({
    html_template: htmlTemplate,
    data: testData,
    engine: 'handlebars'
  })
});
 
const pdfBuffer = await response.arrayBuffer();
fs.writeFileSync('test-invoice.pdf', Buffer.from(pdfBuffer));
console.log('PDF generated: test-invoice.pdf');

Run it. Open the PDF. Does it look right?


Phase 4: Parallel Run (1-2 Weeks)

Don't just flip a switch and hope for the best. Run both systems in parallel.

Dual-Generation Strategy

async function generateInvoicePDF(invoiceData) {
  // Generate with BOTH systems
  const [legacyPDF, reportgenPDF] = await Promise.all([
    generateWithLegacyTool(invoiceData),
    generateWithReportgen(invoiceData)
  ]);
 
  // Use legacy PDF for now
  await sendToCustomer(legacyPDF);
 
  // Store reportgen PDF for comparison
  await storeForReview(reportgenPDF, invoiceData.id);
}

Why do this?

  • Verify reportgen.io produces identical results
  • Catch edge cases you missed in testing
  • Build confidence before cutting over

Monitor & Compare

For 1-2 weeks:

  • Generate PDFs with both systems
  • Compare outputs manually (sample 10-20 PDFs daily)
  • Track any discrepancies

Phase 5: Cutover (1 Day)

Once you've validated everything works, it's time to switch.

Step 1: Update Your Code

Replace your legacy PDF generation:

// Before
const pdf = await legacyPDFTool.generate(template, data);
 
// After
const pdf = await reportgen.generate(template, data);

Step 2: Deploy

Use a feature flag or gradual rollout:

const useLegacy = featureFlags.get('use-legacy-pdf', { userId });
 
if (useLegacy) {
  return await legacyPDFTool.generate(template, data);
} else {
  return await reportgen.generate(template, data);
}

Roll out to 10% of users, then 50%, then 100%.

Step 3: Monitor Closely

Watch for:

  • Error rates
  • Generation times
  • Customer complaints
  • PDF quality issues

Phase 6: Migrate Remaining Templates (Ongoing)

Now that your first template is live, migrate the rest one at a time.

Follow the same process:

  1. Convert template
  2. Test thoroughly
  3. Parallel run
  4. Cutover

Don't rush. Migrate one template per week if needed.


Common Migration Gotchas (And How to Fix Them)

🚨 Gotcha #1: CSS Doesn't Render Correctly

Problem: Flexbox and complex CSS often break in PDF rendering.

Fix: Use table-based layouts and inline styles:

<table width="100%">
  <tr>
    <td>Left column</td>
    <td>Right column</td>
  </tr>
</table>

🚨 Gotcha #2: Custom Fonts Don't Load

Problem: Font files aren't accessible.

Fix: Use absolute URLs or embed fonts:

<style>
  @font-face {
    font-family: 'CustomFont';
    src: url('https://yourdomain.com/fonts/custom.woff2') format('woff2');
  }
  body { font-family: 'CustomFont', sans-serif; }
</style>

🚨 Gotcha #3: Images Are Missing

Problem: Relative image paths don't work.

Fix: Always use absolute URLs:

<!-- Bad -->
<img src="/images/logo.png" />
 
<!-- Good -->
<img src="https://yourdomain.com/images/logo.png" />

Post-Migration: Optimize & Scale

Once you've fully migrated, take advantage of reportgen.io's advanced features:

Use Async Generation for Large PDFs

// For large reports, use async endpoint
const response = await fetch('https://reportgen.io/api/v1/generate-pdf-async', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-API-Key': apiKey
  },
  body: JSON.stringify({
    html_template: largeTemplate,
    data: bigDataset,
    engine: 'ejs'
  })
});
 
const { job_id } = await response.json();
// Poll for completion or use webhooks

Cache Frequently Generated PDFs

const cacheKey = `pdf:${templateId}:${dataHash}`;
let pdf = await cache.get(cacheKey);
 
if (!pdf) {
  pdf = await reportgen.generate(template, data);
  await cache.set(cacheKey, pdf, { ttl: 3600 });
}
 
return pdf;

You're Done! 🎉

Migration complete. You've successfully moved from a legacy PDF tool to reportgen.io.

What you've gained:

  • ✅ Predictable, transparent pricing
  • ✅ Rock-solid reliability
  • ✅ No file size limits
  • ✅ Developer-friendly API
  • ✅ Peace of mind

Next steps:

Need help with your migration? Drop us a line at [email protected] - we've helped dozens of teams make the switch smoothly.