How to Parse Excel Files in n8n: Sheets, Ranges, and Data Types
That Excel report your client just sent? n8n sees nothing but gibberish numbers where dates should be. The cell that clearly shows “March 15th” in Excel arrives as “45366” in your workflow. The carefully formatted spreadsheet with multiple tabs? n8n only reads the first sheet. The data that starts on row 5? Your extraction pulls from row 1 and returns header garbage.
Excel files are everywhere in business automation. Clients send them. APIs return them. Legacy systems export them. And parsing them correctly in n8n requires understanding quirks that trip up even experienced workflow builders.
The Excel Parsing Challenge
The n8n community forums overflow with spreadsheet parsing questions. Users download Excel files from APIs, receive them as email attachments, or pull them from cloud storage. The extraction “works” but produces unusable data. Dates become integers. Multiple sheets get ignored. Specific ranges seem impossible to target.
These problems have consistent solutions. The issue is that Excel files carry hidden complexity that simple extraction can’t address without configuration.
What Makes Excel Different
Excel files aren’t plain text like CSV. They’re compressed binary archives containing:
- Multiple worksheets with independent data
- Cell formatting that affects how values are stored
- Data types including dates stored as serial numbers
- Formulas that may or may not be evaluated
- Named ranges and metadata
When n8n extracts from an Excel file, it reads raw cell values, not the formatted display you see in Excel. This gap between appearance and storage causes most parsing confusion.
What You’ll Learn
- How to configure the Extract from File node for XLSX and XLS files
- Targeting specific sheets by name instead of defaulting to the first one
- Using range notation to extract exactly the cells you need
- Converting Excel’s date serial numbers to actual dates
- Handling common extraction errors with proven troubleshooting steps
- Real workflow patterns for processing Excel files from email, APIs, and uploads
Understanding Excel Files in n8n
Before extracting data, understand how n8n handles Excel files. This foundation prevents the most common parsing mistakes.
XLSX vs XLS vs CSV
n8n supports multiple spreadsheet formats through the Extract from File node. For complete parameter details, see the official n8n Extract from File documentation.
| Format | Extension | Best For | Considerations |
|---|---|---|---|
| XLSX | .xlsx | Modern Excel files | Most common format, supports multiple sheets |
| XLS | .xls | Legacy Excel (pre-2007) | Older format, still used in some systems |
| CSV | .csv | Simple tabular data | Plain text following RFC 4180, no sheets |
| ODS | .ods | LibreOffice/OpenOffice | Open source alternative |
Use XLSX extraction for modern Excel files. Use XLS only when dealing with legacy systems that haven’t upgraded. Use CSV when you have simple comma-separated data without Excel-specific features.
How the Extract from File Node Works
The extraction process follows a specific flow:
- Binary data arrives from a source node (HTTP Request, Gmail, Read Files)
- Extract from File reads the binary content based on format selection
- Each row becomes an n8n item with columns as JSON properties
- Output flows to subsequent nodes for processing
The node doesn’t modify your original file. It reads and converts, outputting JSON that workflows can manipulate.
Binary Data Basics
Excel files travel through n8n as binary data, not JSON. This distinction matters because:
- You cannot read binary content with expressions like
{{ $json.fileContent }} - Binary data lives under a named property (default: “data”)
- The Extract from File node specifically expects binary input
If you add transform nodes between your file source and extraction, you risk losing the binary data. For details on preserving binary data through workflows, see the official n8n binary data documentation.
Your First Excel Extraction
Let’s walk through a complete example: downloading an Excel file and extracting its contents.
Step 1: Get the Excel File
Start with a node that provides the file. Common sources include:
HTTP Request for files from URLs:
- Add an HTTP Request node
- Set Method to GET
- Enter your Excel file URL
- The node automatically handles binary response
Read Files from Disk for local files (self-hosted):
- Add a Read/Write Files from Disk node
- Set Operation to “Read File(s) From Disk”
- Enter the file path:
/path/to/report.xlsx
Gmail/Email nodes for attachments:
- Configure your email trigger
- Attachments appear as binary properties like
attachment_0
Step 2: Add Extract from File
- Add an Extract from File node after your source
- Set Operation to “Extract from XLSX”
- Leave Binary Property as “data” (change if your source uses a different name)
- Open Options and enable Header Row if your first row contains column names
- Click Test step
The Header Row option is critical. When enabled, the first row becomes JSON property names. When disabled, columns are numbered (0, 1, 2, etc.). Most business spreadsheets have headers, so you’ll usually want this enabled.
Step 3: Review the Output
Each Excel row becomes a separate n8n item. If your spreadsheet has headers in row 1, the output looks like:
{
"Name": "Alice Johnson",
"Email": "[email protected]",
"Amount": 150,
"Date": 45366
}
Notice the column headers become JSON keys. Also notice that “Date” is a number, not a date string. This is the Excel serial number issue we’ll solve in the data types section.
Step 4: Use the Data
After extraction, access values with expressions:
{{ $json.Name }} // "Alice Johnson"
{{ $json.Email }} // "[email protected]"
{{ $json.Amount }} // 150
Connect to any node that processes JSON data: databases, APIs, other spreadsheets, or email notifications.
Working with Sheets
Excel files often contain multiple worksheets. By default, n8n extracts only the first sheet. Here’s how to work with specific sheets and multiple sheets.
Default Sheet Behavior
Without configuration, Extract from File reads the first sheet in the workbook. This is the leftmost tab when you open the file in Excel.
If your target data lives on a different sheet, extraction returns the wrong content or empty results.
Specifying Sheet by Name
To extract from a specific sheet:
- Open Extract from File node settings
- Find the Sheet Name option under Options
- Enter the exact sheet name (case-sensitive)
Example: Your file has sheets named “Summary”, “Q1 Data”, and “Q2 Data”. To extract Q2 data:
Sheet Name: Q2 Data
The name must match exactly. “q2 data” won’t work if the actual name is “Q2 Data”.
Finding Sheet Names
If you don’t know the sheet names in a file:
- Open the file in Excel and check the tabs
- Ask the file provider for sheet names
- Use a Code node with a library to list sheets programmatically
For automated workflows where sheet names vary, you’ll need more advanced handling.
Extracting from Multiple Sheets
To process all sheets in one workflow, use a loop pattern:
Trigger → Get Sheet Names → Loop → Extract from Each Sheet → Aggregate Results
Implementation with Code node:
// This runs BEFORE extraction to define which sheets to process
// You'll need the sheet names from your data source or hardcoded
const sheetNames = ['Sales', 'Inventory', 'Customers'];
return sheetNames.map(name => ({
json: { sheetName: name }
}));
Then use an Execute Workflow node or Loop Over Items to extract from each sheet, passing {{ $json.sheetName }} to the Sheet Name option.
Multiple Sheets Workflow Example
Scenario: Monthly report has “Revenue” and “Expenses” sheets. Combine both into a single dataset.
HTTP Request → Split (2 branches)
├── Extract (Sheet: Revenue) → Add Type Field
└── Extract (Sheet: Expenses) → Add Type Field
→ Merge → Process Combined Data
Extract node 1: Sheet Name = “Revenue”
Extract node 2: Sheet Name = “Expenses”
Set node after each: Add {{ "revenue" }} or {{ "expense" }} as a type field
Merge node: Append mode to combine all items
For complex data merging strategies, see our data transformation guide.
Using Range Selection
Sometimes you need specific cells, not the entire sheet. Range selection lets you target exactly the data you want.
Excel Range Notation
Excel uses A1 notation for cell references:
A1= Column A, Row 1B5= Column B, Row 5A1:D10= Rectangle from A1 to D10A:A= Entire column A1:1= Entire row 1
Specifying Ranges in n8n
In the Extract from File node:
- Open Options
- Find the Range setting
- Enter your range in A1 notation
Examples:
| Range | Extracts |
|---|---|
A1:F100 | First 100 rows, columns A through F |
A5:Z1000 | Starting from row 5 (skipping header rows) |
B2:D50 | Specific data block, excluding row 1 headers |
Skipping Header Rows
Many Excel files have metadata before the actual data:
Row 1: Report Title
Row 2: Generated Date
Row 3: (blank)
Row 4: Column Headers
Row 5+: Actual Data
To skip to the real data, set Range to start at the appropriate row:
Range: A4:Z1000
This extracts from row 4 onward, treating row 4 as headers.
Reading Specific Data Areas
Spreadsheets sometimes contain multiple data tables. Use ranges to extract each separately:
First table: A1:D20
Second table: F1:I15
Third table: A25:D40
Create three Extract from File nodes, each targeting one range, then merge or process them independently.
Dynamic Ranges
For files where the data length varies, you have two options:
Option 1: Use a large range
Set Range to A1:Z10000. Empty rows are ignored, so overshooting doesn’t add garbage data.
Option 2: Skip range entirely
Leave Range empty to extract all data from the sheet. Then filter out empty rows in a subsequent Code node:
const items = $input.all();
return items.filter(item => {
// Keep only rows where at least one field has a value
const values = Object.values(item.json);
return values.some(v => v !== null && v !== undefined && v !== '');
});
Handling Data Types
Excel stores data differently than it displays. Understanding these differences prevents the most frustrating parsing issues.
Date Serial Numbers
This is the number one Excel parsing problem. You extract what looks like a date field and get 45366 instead of a readable date.
Why this happens:
Excel stores dates as serial numbers counting days since January 1, 1900 (or 1904 on Mac). The number 45366 means 45,366 days after the epoch date.
The solution:
Convert serial numbers to JavaScript dates in a Code node:
const items = $input.all();
return items.map(item => {
const data = item.json;
// Excel serial number for the date column
const excelDate = data.Date;
// Convert to JavaScript date:
// 25569 = days between Excel epoch (1900-01-01) and JS epoch (1970-01-01)
// 86400 = seconds per day
// 1000 = milliseconds per second
const jsDate = new Date((excelDate - 25569) * 86400 * 1000);
return {
json: {
...data,
Date: jsDate.toISOString().split('T')[0] // Returns "YYYY-MM-DD" format
}
};
});
Expression-based conversion for simpler cases:
{{ new Date(($json.Date - 25569) * 86400 * 1000).toISOString().split('T')[0] }}
For comprehensive date handling, Microsoft’s documentation on Excel date systems explains the epoch calculation.
Time Values
Excel stores times as decimal fractions of a day. The value 0.5 represents noon (12:00 PM), 0.75 represents 6:00 PM, and 0.25 represents 6:00 AM.
When a cell contains both date and time, you get a combined value like 45366.75 (a specific date at 6:00 PM).
Converting time values:
// For time-only values (decimal between 0 and 1)
const excelTime = 0.75; // 6:00 PM
const totalMinutes = Math.round(excelTime * 24 * 60);
const hours = Math.floor(totalMinutes / 60);
const minutes = totalMinutes % 60;
const timeString = `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`;
// Result: "18:00"
// For datetime values, the date conversion already includes time
const excelDateTime = 45366.75;
const jsDate = new Date((excelDateTime - 25569) * 86400 * 1000);
// jsDate includes both date and time components
Empty Cells
Empty cells in Excel can extract as different values depending on the context:
- Truly empty cells: Become
nullor are omitted from the JSON object entirely - Cells with spaces: Extract as empty strings
"" - Cells with formulas returning empty: May become
0or""
Handling empty values:
// Check for empty/null values
const value = item.json.OptionalField;
const hasValue = value !== null && value !== undefined && value !== '';
// Provide defaults
const name = item.json.Name || 'Unknown';
const amount = parseFloat(item.json.Amount) || 0;
Numbers as Text
Sometimes numeric columns extract as strings, especially if cells were formatted as text in Excel.
Symptoms:
- Calculations fail or produce unexpected results
- Values display with quotes in the JSON view
- Comparisons don’t work correctly
The fix:
Parse numbers explicitly:
// In expressions
{{ parseInt($json.Quantity) }} // For integers
{{ parseFloat($json.Price) }} // For decimals
// In Code node
const quantity = parseInt(item.json.Quantity, 10) || 0;
const price = parseFloat(item.json.Price) || 0;
Formulas Appear as Text
If an Excel cell contains =SUM(A1:A10) and you see that formula string in your extraction instead of the calculated value, the file may have:
- Formula cells that weren’t calculated before saving
- The file was exported without evaluating formulas
Solutions:
- Open the file in Excel, ensure formulas are calculated, save again
- Ask the source system to export with “calculated values only”
- There’s no way to evaluate Excel formulas directly in n8n
Boolean Values
Excel represents TRUE/FALSE as actual boolean values. These typically extract correctly, but some systems use:
- 1/0 for true/false
- “Yes”/“No” strings
- “Y”/“N” strings
Normalize in a Set node:
// Convert various truthy values to boolean
{{ $json.Active === true || $json.Active === 1 || $json.Active === 'Yes' || $json.Active === 'Y' }}
Currency and Number Formatting
Excel cells formatted as currency ($1,234.56) may extract as:
- The raw number (1234.56)
- A string with symbols (“$1,234.56”)
- A string with locale-specific formatting
Handle string cleanup if needed:
// Remove currency symbols and commas, then parse
const rawValue = item.json.Amount.replace(/[$,]/g, '');
const amount = parseFloat(rawValue);
Common Excel Parsing Patterns
Real-world workflows combine extraction with business logic. Here are proven patterns for common scenarios.
Email Attachment Processing
Scenario: Clients send weekly reports as Excel attachments. Process each automatically.
Gmail Trigger → Filter (has attachment) → Extract from XLSX → Transform → Database
Gmail Trigger configuration:
- Poll interval: Every 5 minutes or webhook
- Download Attachments: Yes
Key consideration: Gmail outputs attachments with property names like attachment_0. Update the Extract from File “Binary Property” to match:
Binary Property: attachment_0
Filter out emails without attachments:
{{ $json.attachments?.length > 0 }}
For email-specific troubleshooting, see our authentication error guide.
Scheduled Report Imports
Scenario: Daily export from a legacy system lands in an S3 bucket. Import to database.
Schedule Trigger → S3 (download) → Extract from XLSX → Code (transform) → Postgres (upsert)
Schedule: Run daily at 7:00 AM after the export completes
S3 configuration: Download the file, which outputs binary data
Transform Code node:
const items = $input.all();
return items.map(item => {
const data = item.json;
return {
json: {
// Map Excel columns to database fields
customer_id: data['Customer ID'],
name: data['Customer Name']?.trim(),
email: data['Email']?.toLowerCase(),
total_orders: parseInt(data['Order Count'], 10) || 0,
last_order_date: convertExcelDate(data['Last Order']),
imported_at: new Date().toISOString()
}
};
});
function convertExcelDate(serial) {
if (!serial) return null;
return new Date((serial - 25569) * 86400 * 1000).toISOString().split('T')[0];
}
Form Upload Handling
Scenario: Users upload Excel files through a web form. Validate and process the data.
Form Trigger → Validate → Extract from XLSX → Code (validate rows) → IF (valid) → Process / Error
Form Trigger configuration:
- Add a file upload field
- Note the field name for binary property reference
Validation Code node:
const items = $input.all();
const errors = [];
// Check required fields exist in each row
items.forEach((item, index) => {
const row = item.json;
if (!row.Email || !row.Email.includes('@')) {
errors.push(`Row ${index + 1}: Invalid or missing email`);
}
if (!row.Name || row.Name.trim().length < 2) {
errors.push(`Row ${index + 1}: Name is required`);
}
});
if (errors.length > 0) {
return [{ json: { valid: false, errors } }];
}
return [{ json: { valid: true, rowCount: items.length } }];
Cloud Storage Integration
Scenario: Process all Excel files in a Google Drive folder.
Schedule → Google Drive (list files) → Loop → Google Drive (download) → Extract → Process
Google Drive list configuration:
- Filter by MIME type for Excel files
- Target specific folder ID
Loop pattern:
Process one file at a time to avoid memory issues with large files. Use the Loop Over Items node or Execute Workflow with batch processing.
Troubleshooting Excel Errors
When extraction fails or produces unexpected results, use these diagnostic approaches.
Empty Extraction Results
Symptom: Extract from File runs without error but outputs zero items or empty objects.
Possible causes and fixes:
| Cause | Diagnostic | Fix |
|---|---|---|
| Wrong sheet name | Check sheet exists with exact name | Correct Sheet Name option |
| Data starts on later row | Open file in Excel, find actual data start | Set Range to skip header rows |
| Wrong binary property | Check source node’s output for property name | Match Binary Property setting |
| File is corrupted | Try opening file in Excel | Request new file from source |
| Password protection | Can’t extract from protected files | Remove protection or use unprotected version |
Debugging step: Add a Code node after your source to inspect the binary data:
const binary = $input.first().binary;
return [{
json: {
binaryPropertyExists: !!binary?.data,
fileName: binary?.data?.fileName,
mimeType: binary?.data?.mimeType,
fileSize: binary?.data?.data?.length || 0
}
}];
“Binary file not found” Error
Symptom: Node fails with error mentioning binary data not found.
Common causes:
- Wrong property name: Source outputs binary as “attachment_0” but you’re looking for “data”
- Binary lost in transform: A Set or Edit Fields node discarded the binary data
- Source didn’t output binary: File download failed or returned JSON error
Fixes:
- Find the correct property name: Click on your source node, look at the Output panel, and select the Binary tab. The property name appears above the file preview (commonly “data”, “attachment_0”, or “file”). Copy this exact name to your Extract from File node’s Binary Property field.
- Use “Append” mode in Edit Fields nodes, not “Set” mode
- Verify your source node’s test execution shows binary data in its output
For persistent binary issues, our workflow debugger tool can help identify where data gets lost.
Wrong Column Data
Symptom: Extracted values appear in wrong columns or with wrong headers.
Causes:
- First row isn’t actually headers
- Extra columns in the Excel file
- Merged cells in header row
Fixes:
- Examine the actual Excel file structure
- Use Range to skip non-header rows:
A2:Z1000 - If headers are on row 4, set Range to
A4:Z1000
Special Characters and Encoding
Symptom: Names or text contain strange characters, question marks, or boxes.
Cause: Encoding mismatch between file creation and extraction.
Unfortunately, the Extract from File node doesn’t have an encoding option. Workarounds:
- Request files be saved as UTF-8 encoded XLSX
- Use a Code node with proper encoding handling after extraction
- For critical workflows, pre-process files with external tools
Large File Performance
Symptom: Workflow hangs, times out, or crashes with large Excel files.
Thresholds:
- Under 5MB: Usually fine
- 5-20MB: May need optimization
- Over 20MB: Likely needs special handling
Solutions:
- Use ranges to extract only needed rows:
A1:Z10000 - Process in batches using Loop Over Items
- Increase memory for self-hosted n8n
- Split large files before importing to n8n
- Consider cloud processing for very large files
For timeout issues specifically, see our timeout error troubleshooting guide.
Advanced Techniques
Once you’ve mastered basic extraction, these techniques handle complex real-world scenarios.
Processing Multiple Excel Files
Scenario: Download and process all Excel files from a folder or API response.
Pattern:
List Files → Loop Over Items → Download Each → Extract → Aggregate → Output
Memory-safe implementation:
// After Loop Over Items, track which file each row came from
const items = $input.all();
const fileName = $('Download File').item.binary.data.fileName;
return items.map(item => ({
json: {
...item.json,
_sourceFile: fileName
}
}));
Combining Data from Multiple Sheets
Scenario: Consolidate similar data from all sheets into one dataset.
Two-phase approach:
Phase 1: Extract sheet names and create extraction tasks
// Hardcoded or dynamically discovered sheet names
const sheets = ['January', 'February', 'March', 'April'];
return sheets.map(sheet => ({
json: { sheetName: sheet }
}));
Phase 2: Loop, extract each, add source identifier, aggregate
Use Execute Workflow or Sub-Workflow to process each sheet, then merge results.
Data Validation Before Processing
Scenario: Reject files that don’t match expected structure.
Validation Code node:
const items = $input.all();
const expectedColumns = ['Name', 'Email', 'Amount', 'Date'];
// Check first row has expected columns
const firstItem = items[0]?.json || {};
const actualColumns = Object.keys(firstItem);
const missing = expectedColumns.filter(col => !actualColumns.includes(col));
const extra = actualColumns.filter(col => !expectedColumns.includes(col) && !col.startsWith('_'));
if (missing.length > 0) {
throw new Error(`Missing required columns: ${missing.join(', ')}`);
}
if (extra.length > 0) {
// Warning only, don't fail
console.log(`Unexpected columns found: ${extra.join(', ')}`);
}
return items;
Error Handling Patterns
Production workflows need graceful error handling:
Trigger → TRY (Extract + Process) → Success Path
↓ (on error)
Error Handler → Notify + Log → Quarantine File
Error handler workflow:
- Connect an Error Trigger node workflow
- Capture error details and original file information
- Send notification (Slack, email) with error context
- Move failed file to quarantine folder for manual review
For building robust error handling, see our Code node JavaScript patterns.
Frequently Asked Questions
Why do my Excel dates show as numbers like 45234?
Excel stores dates internally as serial numbers representing days since January 1, 1900. The number 45234 means 45,234 days after that date.
n8n extracts the raw stored value, not the formatted display. You must convert these serial numbers to actual dates.
Conversion formula:
// In a Code node or expression
const jsDate = new Date((excelSerial - 25569) * 86400 * 1000);
// 25569 = days between Excel epoch (1900) and JavaScript epoch (1970)
// 86400 = seconds per day, 1000 = milliseconds
As an expression:
{{ new Date(($json.DateColumn - 25569) * 86400 * 1000).toISOString().split('T')[0] }}
This returns dates in “YYYY-MM-DD” format. Microsoft’s date system documentation explains the underlying calculation.
How do I extract data from a specific sheet in my Excel file?
By default, n8n extracts from the first sheet only. To target a specific sheet:
- Open the Extract from File node
- Go to Options
- Find Sheet Name
- Enter the exact sheet name (case-sensitive)
Example: If your sheet is named “Q2 Sales”, enter exactly:
Sheet Name: Q2 Sales
If you don’t know the sheet names, open the file in Excel and check the tabs at the bottom. The name must match exactly, including spaces and capitalization.
Can I read only certain columns or rows from an Excel file?
Yes, use the Range option in Extract from File.
Range notation:
A1:D100= Columns A through D, rows 1 through 100A5:Z1000= Skip first 4 rows, read from row 5B2:F50= Specific data block
Common scenarios:
| Situation | Range Setting |
|---|---|
| Skip title rows 1-3, data starts row 4 | A4:Z10000 |
| Only need columns A, B, C, D | A1:D10000 |
| Data in specific area | B5:E50 |
If you leave Range empty, n8n extracts all data from the sheet. After extraction, use a Code node or Filter node to remove unwanted columns.
Why does my Excel extraction return empty data?
Empty extraction has several common causes:
1. Wrong sheet name
If the Sheet Name doesn’t match exactly (including capitalization), extraction fails silently. Remove the sheet name to extract from the first sheet, then verify your data.
2. Wrong binary property
Your source node may output binary data under a name other than “data”. Check the source output and match the Binary Property setting.
3. Data starts below row 1
If your file has title rows or metadata before the data, set Range to start at the actual data row. For example, if data starts at row 5: A5:Z10000.
4. File is password-protected
n8n cannot extract from password-protected Excel files. Remove the protection or use an unprotected version.
Debugging approach:
Add a Code node after your source to inspect the binary:
const binary = $input.first().binary?.data;
return [{ json: {
exists: !!binary,
fileName: binary?.fileName,
size: binary?.data?.length
}}];
If exists is false or size is 0, the issue is with your source node, not extraction.
How do I handle Excel files with multiple sheets?
The Extract from File node processes one sheet at a time. For multiple sheets, use one of these approaches:
Option 1: Multiple Extract nodes (known sheets)
Create parallel branches, each with an Extract from File node targeting a different Sheet Name, then merge the results.
Option 2: Loop pattern (dynamic sheets)
// Create items for each sheet
const sheets = ['Sheet1', 'Sheet2', 'Sheet3'];
return sheets.map(name => ({ json: { sheetName: name } }));
Then use Loop Over Items with the sheet name passed to each extraction.
Option 3: Sub-workflow
Create a sub-workflow that extracts from a single sheet (sheet name as input parameter), then call it multiple times from your main workflow.
The data transformation guide covers merging data from multiple sources if you need to combine sheet data.
Next Steps
You now have the knowledge to parse virtually any Excel file in n8n. Bookmark this page for reference when you encounter specific parsing challenges.
Continue learning:
- Extract from File Node Reference for complete parameter documentation
- Convert to File Node for creating Excel files from workflow data
- Data Transformation Guide for reshaping extracted data
- Code Node JavaScript Patterns for custom transformation recipes
- Workflow Debugger Tool for troubleshooting extraction errors
For complex Excel processing workflows or production deployment, our n8n workflow development services and consulting packages provide expert assistance with your automation challenges.