transform.xlsx-to-json reads one worksheet from an uploaded .xls or .xlsx file into rows, an array of objects.
Use it when a workflow needs tabular data from a spreadsheet before a script, extract, or transform.json-to-xlsx. The step keeps a single selected sheet. It does not calculate formulas, reconstruct merged cells, or coerce values into a business schema.
Zero-config YAML stays compatible: the first effective row is the header, values are typed cached results, empty cells become "", and blank rows are skipped. Default output is rows (plus fileId when CSV is stored). Optional fields add headerless files, named or positional projection, displayed text, a rectangular A1 range, and blank-cell policy. Set includeMetadata: true to add sheet metadata and warning diagnostics. Warnings are still logged when metadata is off.
When to use it
Supported input is detected from bytes, not the filename: BIFF
.xls and OOXML .xlsx. Password-protected, corrupt, .xlsm, .xlsb, CSV, and ODS files fail clearly.
Configuration
Configuration goes inside the step’swith: block.
string
required
File input - template expression e.g. {{input.document}} resolving to a scoped $file artifact at runtime
integer | string
Sheet to read: 0-based index or exact sheet name. Omit for the first sheet.
boolean
default:"false"
If true, also write CSV to storage and include fileId. Zero-config uses the historical full-sheet SheetJS CSV. When columns, range, headerRow, valueMode, blankCells, or blankRows are set, CSV matches that projection.
boolean
default:"false"
If true, include sheet metadata and diagnostics in the step output. Omit to keep output as rows (and fileId when outputCsv is true). Warnings are still logged when this is false.
string
Output CSV filename when outputCsv is true - supports LiquidJS e.g. {{filename}}.csv
boolean | integer
Header row: a positive 1-based Excel row, or false to keep the first effective row as data. Omit to use the first effective row as the header. When range is set and this is omitted, the first range row is the header.
array<object>
Ordered output columns. Each item needs a key and exactly one source: index (0-based absolute column) or header (exact displayed header text). Named header sources require a header row. Omit to keep every column in the effective range.
"raw" | "displayed"
default:"raw"
raw (default) returns typed cached cell values. displayed returns formatted cell text (dates, leading zeros, punctuation, diacritics, embedded newlines). Formulas are never calculated.
string
Optional rectangular A1 range without a sheet qualifier, e.g. A1:D20. Disjoint ranges are rejected.
"empty-string" | "null" | "omit"
default:"empty-string"
How truly empty cells appear in each row object. Default empty-string. 0, false, and a formula that cached an empty string are not empty cells.
"skip" | "keep"
default:"skip"
skip (default) drops rows whose projected columns are all truly empty. keep retains them. Detection uses projected columns only.
object
Optional workload caps that can only lower the server defaults. Omitted fields use the server defaults.
Output
Array of row objects (first row = headers as keys unless headerRow is false)
File ID of stored CSV when outputCsv is true
Selected sheet metadata after projection. Present only when includeMetadata is true.
Non-fatal warnings collected while reading the sheet. Present only when includeMetadata is true. Warnings are still logged when metadata is omitted.
Limits and CSV
Server conversion caps (maxRows 100,000, maxColumns 256, maxCells 5,000,000) apply to the selected effective range that is actually materialized. With no range, that is the selected sheet’s used range (!ref). A huge sparse used range on a sibling sheet does not fail a small selected sheet. ZIP archives are still checked for inflate/path/entry safety before parse, and worksheet addresses must sit inside the Excel grid (1,048,576 rows × 16,384 columns). Legacy .xls files skip ZIP inspection; they still use the input-size cap, sparse reads, and the selected effective-range ceilings.
Zero-config outputCsv writes the historical full-sheet SheetJS CSV. When columns, range, headerRow, valueMode, blankCells, or blankRows are set, the CSV follows that projection.