The previous lesson's cfhtmltopdf is Adobe-only. cfdocument is the tag that actually runs on both engines, converting everything between its start and end tags into PDF (or, on Adobe, FlashPaper) output, just rendered by a different engine underneath depending on where it runs.
Learning Objectives
After completing this lesson, you'll be able to:
- Generate a PDF from CFML/HTML content with cfdocument.
- Configure page format, orientation, and security attributes.
- Recognize where Lucee's rendering genuinely differs, engine choice, units, and font handling.
One Tag, Two Engines
CFML/HTML Between the Tags
Which Engine?
Adobe's Engine, or Lucee's Classic/Flying Saucer
PDF (or FlashPaper) Output
A Basic Example
<cfdocument format="pdf" filename="#getTempDirectory()#mydoc.pdf" overwrite="yes">
<h1>Hello ColdFusion</h1>
<p>Generated at: <cfoutput>#timeFormat(now())#</cfoutput></p>
</cfdocument>cfdocument's Core Attributes
| Attribute | Meaning |
|---|---|
| format | pdf or FlashPaper (required) |
| filename | Where to save the output; omit it to write to the response stream |
| pagetype | letter (default), legal, A4, A5, B4, B5, B4-JIS, B5-JIS, or custom |
| orientation | portrait (default) or landscape |
| encryption | none (default), 40-bit, or 128-bit |
| fontembed | yes (default), no, or selective |
| bookmark | Enables PDF bookmarks (default no) |
| backgroundVisible | Whether background colors/images print (default no) |
| localurl | Retrieve referenced images from local disk instead of over HTTP (default no) |
| src / srcfile | Generate from an external file instead of the tag body |
| authUser / authPassword | Basic authentication credentials when fetching a remote src |
| proxyPort | Defaults to 80 when a proxy is configured |
| overwrite | Whether to replace an existing file at filename (default no) |
pagetype actually defaults to letter on both cfdocument and cfhtmltopdf, they're consistent with each other here, it's still worth setting explicitly rather than relying on either default.
Real Engine Differences on Lucee
| Aspect | Detail |
|---|---|
| Rendering engine | type="modern" (Flying Saucer, the default) or type="classic" (the older PD4ML-based engine), configurable per-document, or globally via this.pdf.type in Application.cfc |
| Units | Adds px and pt alongside in and cm, which Adobe's cfdocument doesn't document |
| Font handling | The classic engine references font-family names from pd4fonts.properties; Flying Saucer uses .ttf filenames directly, with case sensitivity applied |
| Format support | Word and Excel conversion is unavailable in Lucee's cfdocument |
| Packaging | Requires the PDF Extension for Jakarta EE (Lucee 7+), it's no longer bundled by default |
Switching a document from Lucee's classic engine to Flying Saucer (or the reverse) isn't guaranteed to produce visually identical output, verify existing documents after a migration.
A Real Example: Choosing the Rendering Engine Explicitly (Lucee)
<cfdocument format="pdf" type="modern" filename="report.pdf" overwrite="yes">
<h1>Quarterly Report</h1>
</cfdocument>component {
this.pdf.type = "modern";
}Common Beginner Mistakes
Confusing localUrl with a general performance setting
It specifically controls whether referenced images are pulled from local disk instead of over HTTP, it doesn't affect anything else about how the document renders.
Assuming Flying Saucer output looks pixel-identical to the classic engine's
They're genuinely different renderers, an existing document may need visual verification after switching engines.
Forgetting the PDF Extension requirement on Lucee 7+
cfdocument requires the PDF Extension for Jakarta EE to be installed on Lucee 7 and later, it isn't bundled by default anymore.
Referencing a font by its font-family name on Flying Saucer
Flying Saucer expects the actual .ttf filename (case-sensitive), unlike the classic engine's pd4fonts.properties-based font-family names.
Best Practices
- Set pagetype and orientation explicitly rather than relying on the default, even though cfdocument and cfhtmltopdf do actually agree on letter.
- Pin the rendering engine explicitly (type or this.pdf.type) on Lucee rather than depending on whatever the current default happens to be.
- Verify visual output after switching a Lucee document between the classic and Flying Saucer engines.
- Use localurl when the document references images already on local disk, to avoid unnecessary HTTP round-trips during generation.
Interview Questions
Why is cfdocument the right choice when the exact same code must run on both Adobe ColdFusion and Lucee?
It's the one PDF-generation tag both engines implement, cfhtmltopdf is Adobe-only. The underlying rendering engine differs (Adobe's engine vs Lucee's classic/Flying Saucer), but the tag itself is shared.
What's the real difference between Lucee's classic and Flying Saucer engines?
Flying Saucer is the modern default with full CSS 2.1 support, smaller output, and lower resource use; classic is the older PD4ML-based engine kept for compatibility. They aren't guaranteed to render the same input identically.
Why might referencing a font work on Lucee's classic engine but not on Flying Saucer?
Classic uses font-family names from pd4fonts.properties, Flying Saucer expects the actual .ttf filename, case-sensitively, a different lookup mechanism entirely.
Summary
In this lesson, you generated a PDF with cfdocument, configured page format and security attributes, and covered real engine differences on Lucee: Flying Saucer vs the classic engine, extra unit support, font-handling differences, and the PDF Extension requirement on Lucee 7+.
What's Next?
The next lesson covers cfdocumentitem, cfdocument's sub-tag for page breaks, running headers, and footers.