Migration - Upgrades

How to Migrate ColdFusion PDF and Excel Reports

Why upgrading ColdFusion PDF and Excel report generation matters

PDF and Excel exports are often the backbone of invoices, statements, dashboards, and analytics sent to customers and stakeholders. Over time, the underlying engines, libraries, and runtimes behind ColdFusion’s PDF and spreadsheet Features evolve. Migrating ensures better rendering quality, Security patches, Java and OS compatibility, improved CSS/HTML support, and enhanced Scalability. It also reduces risk due to deprecated APIs, outdated libraries (e.g., older iText or Apache POI versions), and unsupported server versions. A careful Migration preserves report fidelity while unlocking modern capabilities such as headless HTML-to-PDF engines, streaming Excel for large datasets, and container-friendly deployments.


Prerequisites / Before You Start

  • Backups and Version control

    • Full backup of application code, ColdFusion Administrator settings, data sources, Custom tags/components, and Scheduled tasks.
    • Export CF Admin settings if possible (using CF Admin API or documentation screenshots).
    • Confirm your repository (Git) has tagged releases and branches for hotfixes and rollback.
  • Target Versions

    • Decide the runtime: Adobe ColdFusion 2021/2023 or Lucee 5.4+.
    • Target Java 11 or 17 (aligned with your CFML engine’s support matrix).
    • Identify the desired Apache POI version (affects cfspreadsheet behavior under different CF versions).
    • Confirm PDF engine: cfdocument (legacy), cfhtmltopdf (WebKit-based), or external Java libraries (PDFBox, iText 7, OpenPDF).
  • Dependencies, Licenses, and Libraries

    • Inventory any direct Java library calls (createObject(“java”, …)) for PDF/Excel. Check licenses: iText 2.x (LGPL/MPL), iText 5/7 (AGPL/commercial), Apache POI (Apache 2.0), PDFBox (Apache 2.0).
    • If you rely on cfhtmltopdf, plan to install and configure Adobe’s PDFg Service (Add-on Services).
    • Verify font files and font Licensing for embedding in PDFs.
  • Infrastructure and Capacity

    • 64-bit JVM and adequate heap (e.g., -Xms2g -Xmx4g) for large PDFs and spreadsheets.
    • Disk space for temporary files, caching, and staging outputs.
    • If containerizing, define base images (e.g., CommandBox + Adobe CF/Lucee) and volume mounts for fonts and templates.
  • Security and Compliance

    • TLS 1.2+ for any remote resources used in report templates (images/CSS).
    • Validate Sandbox security, lockdown guides for Adobe CF, and resource whitelisting.
    • PII redaction and secure storage for generated files.
  • Testing Artifacts

    • Golden sample reports for visual and data comparisons.
    • Acceptance criteria for formatting, pagination, fonts, images, hyperlinks, macros, and formulas.
See also  How to Handle Deprecated Tags During ColdFusion Upgrade

Step-by-Step Migration guide

1) Inventory and classify your reports

  • PDF
    • Identify usage of: , , , PDF merge/split, password protection, bookmarks, table-of-contents, and dynamic images.
    • Note HTML/CSS complexities: advanced CSS3, JavaScript, web fonts, SVGs.
  • Excel
    • Identify usage of: , cfscript spreadsheet functions, CSV exports, macros, pivot tables, conditional formatting.
    • Note dataset sizes, memory footprint, streaming needs, and data sources.

Document a matrix: source file, report type (PDF/Excel), inputs (queries, APIs), template (CFM/HTML), output location, recipients, schedule/trigger.

2) Prepare the target runtime

  • Install your chosen CFML engine:
    • Adobe CF 2021/2023 or Lucee 5.4+. Match a compatible Java.
    • For Adobe CF: install updates and Add-on Services (includes PDFg) if using cfhtmltopdf.
  • If containerizing:
    • Use CommandBox-based images or vendor images.
    • Mount volumes for logs, fonts (/usr/share/fonts), and templates.
  • Configure datasources, mail servers, file permissions, and caching in CF Admin.
  • Increase JVM memory for report-heavy workloads:
    • Example JVM args:
      • -Xms2g -Xmx4g -XX:+UseG1GC -Djava.awt.headless=true
      • -Dsun.java2d.renderer=sun.java2d.marlin.MarlinRenderingEngine

3) Fonts, images, and resources

  • Collect all fonts used in PDFs (e.g., corporate fonts) and install on servers or package into the container image.
  • Confirm font embedding behavior in cfdocument/cfhtmltopdf (embed or subset).
  • Switch absolute URLs to server-relative or secure HTTPS references.
  • Consolidate and version CSS and assets for consistent rendering.

4) Migrate PDF reports

Choose the approach that best fits your report complexity and Performance needs.

Approach A: Stay with cfdocument (minimal change)

  • Pros: Minimal refactor if you already rely on .
  • Cons: CSS/HTML support can be limited compared to newer engines.

Example:

Old:
cfm


Invoice ##url.invoiceId#


Item Price


Refinements:

  • Use inline styles or minimal CSS for predictable layout.
  • Ensure images are reachable via paths permitted by sandbox/security.
  • Explicitly set page size and margins to control pagination:
    cfm

Approach B: Switch to cfhtmltopdf + PDFg Service (better HTML/CSS support)

  • Pros: Better support for advanced CSS, complex layouts, and web fonts.
  • Cons: Requires PDFg Service installation and Configuration (local or remote).

Set up PDFg in CF Administrator:

  • Server settings > HTML to PDF > Configure Host/Port
  • Test connection using the Administrator test button.

Example:
cfm


Acme Corp



Invoice ##url.invoiceId#




Page: of


Tips:

  • Host fonts locally and reference with @font-face for consistent results.
  • Avoid client-side JS; pre-render data and use server-side formatting.

Approach C: Offload to Java libraries (PDFBox, iText 7)

  • Pros: Fine-grained control, advanced PDF operations (redaction, digital signatures).
  • Cons: More code; Licensing considerations for iText.

Example (merging PDFs with PDFBox):
cfscript
pdfMerger = createObject(“java”, “org.apache.pdfbox.multipdf.PDFMergerUtility”);
pdfMerger.addSource(expandPath(“/out/part1.pdf”));
pdfMerger.addSource(expandPath(“/out/part2.pdf”));
pdfMerger.setDestinationFileName(expandPath(“/out/merged.pdf”));
pdfMerger.mergeDocuments(javaCast(“int”, org.apache.pdfbox.io.MemoryUsageSetting.setupTempFileOnly()));

Use this for specialized Features (e.g., encryption, annotations) not easily handled by tags.

5) Migrate Excel reports

Using cfspreadsheet (tag/script)

Most Adobe CF and Lucee environments bundle Apache POI. Use streaming for large datasets and control memory usage.

See also  How to Switch from ColdFusion to Modern CFML Frameworks

Create Workbook:
cfscript
spreadsheet = spreadsheetNew(“Sales”);
spreadsheetAddRow(spreadsheet, [“Region”, “Product”, “Qty”, “Total”]);
for (row in qSales) {
spreadsheetAddRow(spreadsheet, [row.region, row.product, row.qty, row.total]);
}
spreadsheetFormatColumn(spreadsheet, {dataformat:”$#,##0.00″}, 4);
spreadsheetWrite(spreadsheet, expandPath(“/out/sales.xlsx”), true);

Large exports (streaming):

  • Some engines support streaming under the hood; if needed, call Apache POI SXSSF directly for huge datasets.

Example with Apache POI (SXSSF):
cfscript
XSSFWorkbook = createObject(“java”,”org.apache.poi.xssf.usermodel.XSSFWorkbook”);
SXSSFWorkbook = createObject(“java”,”org.apache.poi.xssf.streaming.SXSSFWorkbook”).init(XSSFWorkbook.init(), javaCast(“int”, 1000));
sheet = SXSSFWorkbook.createSheet(“Sales”);

rownum = 0;
header = [“Region”,”Product”,”Qty”,”Total”];
r = sheet.createRow(javacast(“int”, rownum++));
for (i=1; i<=arrayLen(header); i++) { cell = r.createCell(javacast(“int”, i-1)); cell.setCellValue(header[i]); }

for (s in qSales) {
r = sheet.createRow(javacast(“int”, rownum++));
r.createCell(0).setCellValue(s.region);
r.createCell(1).setCellValue(s.product);
r.createCell(2).setCellValue(javaCast(“double”, s.qty));
r.createCell(3).setCellValue(javaCast(“double”, s.total));
}

fileOut = createObject(“java”,”java.io.FileOutputStream”).init(expandPath(“/out/sales.xlsx”));
SXSSFWorkbook.write(fileOut);
fileOut.close();
SXSSFWorkbook.dispose(); // frees temp files

Best practices:

  • Use numeric cell types for numbers/dates to avoid Excel “Number Stored as Text.”
  • Use styles sparingly; avoid per-cell styles for millions of cells.

6) Replace deprecated or changed behaviors

  • Audit for deprecated CF functions or tag attributes.
  • For iText 2.x custom Java calls, either:
    • Refactor to PDFBox/OpenPDF, or
    • Adopt iText 7 with correct licensing.
  • For HTML-based “fake Excel” (sending HTML as application/vnd.ms-excel), migrate to real XLSX for better compatibility.

7) Update file streaming, headers, and caching

Serve files with correct headers:
cfm


cfm


Set cache-control and ETag headers if hosting static outputs behind a CDN.

8) Migrate Scheduled tasks and integrations

  • Recreate scheduled tasks in the new CF Admin or cron/Kubernetes CronJobs.
  • For email attachments, confirm mail server configs and SSL/TLS.
  • Verify S3/Azure Blob uploads if you store outputs in object storage (use official SDKs or cfS3/cfAzureBlob).

9) Automate tests and visual validation

  • Unit tests for data correctness (row counts, sums, formulas).
  • Visual/PDF tests: compare page count, bookmarks, text extraction via PDFBox.
  • Baseline Excel validations: sheet count, column headers, data types.

10) Cutover and rollback plan

  • Run parallel for a cycle: old vs new outputs to stakeholders for sign-off.
  • Maintain a rollback path: DNS/route switch or feature flags.
  • Monitor logs, memory, CPU, and queue times during first full cycle.

Risks, Common Issues, and How to Avoid Them

  • Font substitution leading to layout shifts
    • Install required fonts; set explicit font-family; verify embedding.
  • CSS differences between engines
    • Prefer cfhtmltopdf for complex CSS; reduce reliance on unsupported CSS/JS.
  • OutOfMemoryError / temp file growth
    • Increase heap; use streaming (SXSSF) for Excel; configure temp directories with sufficient space; dispose of resources.
  • Licensing pitfalls with iText
    • Audit Java calls; replace with OSS alternatives (PDFBox/OpenPDF) or purchase a proper license for iText 7.
  • Image/asset loading failures
    • Use absolute HTTPS URLs or whitelisted local paths; verify ColdFusion sandbox permissions.
  • Date and number formatting inconsistencies
    • Explicitly set locales, time zones, and numeric formats in code.
  • Different PDF rendering between environments
    • Standardize fonts and CSS; use the same PDF engine across environments; accept minor pixel differences and validate via text extraction and pagination rather than pixel-perfect diffs.
  • Locked files on Windows
    • Close all streams and file handles; use try/finally for cleanup.

Post-Migration Checklist / Validation Steps

  • Environment

    • CF version, updates, and Java version are as planned.
    • PDFg Service installed and reachable (if using cfhtmltopdf).
    • Fonts present and embeddable; confirm with sample PDFs.
  • Functionality

    • All scheduled reports run and deliver on time.
    • PDF reports open in Acrobat Reader and browser PDF viewers without warnings.
    • Excel files open in Microsoft 365 and LibreOffice; no “repaired records” prompts.
  • Data and Layout

    • Row counts, totals, and key metrics match baseline.
    • Pagination, headers/footers, and page counts are as expected.
    • Bookmarks, hyperlinks, and table of contents function.
  • Performance

    • Generation time within SLA; no memory spikes or timeouts.
    • Temporary directories cleaned regularly; no runaway disk usage.
  • Security and Compliance

    • Sensitive outputs stored securely; restricted access.
    • Logs do not contain PII.
    • TLS used for remote assets and mail.
  • Monitoring and Alerts

    • Error logging, stack traces, and metrics wired into your APM.
    • Alerts for failed jobs or large queue backlogs.
See also  How to Migrate ColdFusion Sessions During Server Switch

Sample PDF text check via CF and PDFBox:
cfscript
// Example: simple content check using PDFBox (ensure PDFBox jars are on classpath)
PDFTextStripper = createObject(“java”, “org.apache.pdfbox.text.PDFTextStripper”);
PDDocument = createObject(“java”, “org.apache.pdfbox.pdmodel.PDDocument”);
doc = PDDocument.load( createObject(“java”,”java.io.File”).init( expandPath(“/out/invoice.pdf”) ) );
stripper = PDFTextStripper.init();
text = stripper.getText(doc);
doc.close();
if ( !findNoCase(“Invoice”, text) ) {
writeLog(file=”reportValidation”, text=”Invoice keyword missing in output PDF”);
}


Reference mapping and Configuration snippets

Feature mapping table:

  • PDF generation
    • Keep for simple layouts.
    • Prefer for complex CSS and better rendering.
    • Use PDFBox/iText for merging, encryption, digital signatures.
  • Excel generation
    • Use for standard cases.
    • Use Apache POI SXSSF for very large datasets.
  • Deployment
    • Adobe CF Add-on Services for PDFg.
    • Container images via CommandBox for Adobe CF or Lucee.

CF Admin headers example for attachment streaming:
cfm


JVM font rendering flags (optional):

  • -Djava.awt.headless=true
  • -Dawt.useSystemAAFontSettings=on
  • -Dswing.aatext=true

FAQ

How do I decide between cfdocument and cfhtmltopdf?

Use cfdocument for simpler layouts and minimal changes; it’s fast for basic templates. Choose cfhtmltopdf when you need better CSS support, web fonts, precise pagination, headers/footers with page numbers, or complex, responsive-like layouts. Remember that cfhtmltopdf requires the PDFg Service to be installed and configured.

What’s the safest path if my code calls iText directly?

Audit versions and licenses first. If you’re on legacy iText 2.x, consider migrating to PDFBox or OpenPDF to avoid AGPL constraints, unless you plan to buy an iText 7 commercial license. Re-implement only the features you use (merge, watermark, sign) and validate results with sample documents.

How do I prevent Excel exports from running Out of memory?

Use streaming approaches. With cfspreadsheet, avoid building huge in-memory arrays when possible. For very large reports, call Apache POI’s SXSSF, which writes to disk-backed buffers. Limit cell styles, avoid per-cell formatting loops, and write rows incrementally.

My PDFs look different After migration. How do I ensure fidelity?

Lock down fonts (install and embed), minimize unsupported CSS, and standardize engines across environments. Validate by comparing page counts, text presence, and key visual anchors. Expect minor rendering differences across engines; focus on functional equivalence and output readability.

Can I run the PDF/Excel generation in containers or Serverless?

Yes. Package fonts and templates into your image, ensure sufficient memory and temp storage, and mount a volume for outputs. For Serverless, watch cold starts and execution time limits; consider breaking large reports into smaller batches or generating asynchronously via queues and workers.

About the author

Aaron Longnion

Aaron Longnion

Hey there! I'm Aaron Longnion — an Internet technologist, web software engineer, and ColdFusion expert with more than 24 years of experience. Over the years, I've had the privilege of working with some of the most exciting and fast-growing companies out there, including lynda.com, HomeAway, landsofamerica.com (CoStar Group), and Adobe.com.

I'm a full-stack developer at heart, but what really drives me is designing and building internet architectures that are highly scalable, cost-effective, and fault-tolerant — solutions built to handle rapid growth and stay ahead of the curve.