cfspreadsheet reads, writes, and updates Excel spreadsheet files (XLS/XLSX) directly in CFML, converting between a query, a spreadsheet object, and the actual file on disk. It's an Adobe ColdFusion tag, Lucee has no native equivalent, though it does offer a related SpreadsheetNew() function.
Learning Objectives
After completing this lesson, you'll be able to:
- Read an Excel file into a query with cfspreadsheet.
- Write a new Excel file from a query or a spreadsheet object.
- Add a sheet to an existing file with update, and know its real limitation.
- Explain why cfspreadsheet is Adobe ColdFusion-only.
How cfspreadsheet Fits In
Query or Spreadsheet Object
action="read" / "write" / "update"
Excel File (XLS/XLSX)
On Disk or Back Into a Query
A Basic Read Into a Query
<cfspreadsheet action="read" src="#expandPath('./employees.xlsx')#" query="employees" headerrow="1">cfspreadsheet's Attributes
| Attribute | Meaning |
|---|---|
| action | read, write, or update (required) |
| src | File path to read from (required for read) |
| filename | Output file path (required for write/update) |
| name / query | A variable to hold spreadsheet data, or a query to read from/write to (one is required) |
| sheet / sheetname | Targets a specific sheet by number or name |
| headerrow | Which row holds column names, when reading into a query |
| excludeHeaderRow | Whether to leave the header row out of the query result (default false) |
| columns / rows | Limits reading to a specific range |
| columnnames | Custom comma-delimited column names, overriding the header row |
| format | csv or html, for reading/exporting as something other than a spreadsheet object |
| overwrite | Whether write can replace an existing file (default false) |
| autosize | Auto-resizes columns to fit content on write (default true) |
| password | Protects the file (mandatory for write/update as of the ColdFusion 2025 release) |
A Real Example: Building a Spreadsheet Object, Then Writing It
theSheet = spreadsheetNew("Sheet1");
spreadsheetAddRows(theSheet, myQuery);<cfspreadsheet action="write" filename="#expandPath('./mydata.xlsx')#" name="theSheet" overwrite="true">spreadsheetNew() and spreadsheetAddRows() build up an in-memory spreadsheet object first, useful when the data needs shaping before it's actually written, rather than writing a query directly.
A Real Limitation: update Can Only Add Sheets
action="update" adds a new sheet to an existing Excel file, it cannot modify a sheet that's already there. Changing existing content means reading the file, making the change to the resulting query or spreadsheet object, and writing it back out.
A Real Gotcha: Password Requirement Since ColdFusion 2025
As of the ColdFusion 2025 release, password is mandatory for write and update, code that omitted it on earlier versions needs an explicit password value to keep working.
A Real Limitation: Two Excel 2007 Functions Aren't Supported
Adobe's own documentation notes that SpreadSheetAddSplitPane and SpreadSheetAddFreezePane, otherwise part of the same spreadsheet function family, aren't supported for Excel 2007-format files, the two documented exceptions to otherwise full Excel 2007 support.
Why This Tag Doesn't Exist on Lucee
Lucee's own documentation states plainly that cfspreadsheet is not supported by Lucee. It does offer a native SpreadSheetNew() function as a partial alternative, and its own docs point toward community extensions (like spreadsheet-cfml) for the rest of the gap, rather than a built-in tag.
Common Beginner Mistakes
Assuming update can modify an existing sheet's content
It can only add a new sheet. Changing existing content means reading the file, modifying the resulting query or spreadsheet object, and writing it back out.
Porting cfspreadsheet-based code to Lucee unchanged
The tag doesn't exist there at all. Lucee's native SpreadSheetNew() function, or a community extension, is the actual equivalent, not a direct port.
Forgetting the password requirement on ColdFusion 2025
write and update require an explicit password value as of that release, code written against an earlier version may need updating.
Best Practices
- Use spreadsheetNew()/spreadsheetAddRows() to build a spreadsheet object first when the data genuinely needs shaping before it's written.
- Set headerrow or columnnames explicitly when reading, rather than relying on default behavior.
- Check Lucee's SpreadSheetNew() function or a community extension before assuming Adobe cfspreadsheet-based code will run unchanged there.
- Update code targeting ColdFusion 2025 to supply an explicit password on write/update, it's no longer optional.
Interview Questions
What's the real limitation of cfspreadsheet's update action?
It can only add a new sheet to an existing file, it cannot modify a sheet that's already there.
Why would cfspreadsheet-based code fail entirely on Lucee?
The tag isn't supported by Lucee at all. Lucee offers a native SpreadSheetNew() function and points toward community extensions instead of a built-in tag equivalent.
What changed about cfspreadsheet's password attribute in ColdFusion 2025?
It became mandatory for the write and update actions, previously optional code needs an explicit password value to keep working.
Summary
In this lesson, you read an Excel file into a query, built and wrote a spreadsheet object with spreadsheetNew()/spreadsheetAddRows(), covered update's real limitation to adding sheets only, the ColdFusion 2025 password requirement, and why cfspreadsheet has no native Lucee equivalent.
What's Next?
The next lesson covers cfchart, generating charts and graphs directly from a query.