n8n Read/Write Files Node: Read, Write, and Process Local Files in Your Workflows [Free Workflow JSON]
If you're running n8n self-hosted, sooner or later you'll need to read a file from disk, write output to a file, or pass a binary attachment through a workflow. The Read/Write Files from Disk node (and its companion Convert to/from File node) are the tools for that. This guide covers every operation, the most common gotchas, and three production-ready patterns.
What the Node Does
n8n has two nodes for file work on a self-hosted instance:
| Node | Purpose |
|---|---|
| Read/Write Files from Disk | Read from or write to the server's local filesystem |
| Convert to/from File | Convert n8n item data to a binary file object (or the reverse) — no disk I/O |
Cloud / n8n.cloud users: The Read/Write Files node is not available on n8n Cloud because there's no persistent local filesystem. Use the S3 node, Google Drive node, or another cloud storage integration instead.
Read/Write Files from Disk
Operations
Read File(s) From Disk
Reads one or more files and outputs them as binary data.
File Path: /data/reports/monthly.csv
Property Name: data ← the binary property name on the output item
You can read multiple files by using an expression referencing an input field, or by providing a glob pattern in some versions.
Write File to Disk
Writes binary data from a previous node to a path on disk.
File Path: /data/output/{{ $now.format('yyyy-MM-dd') }}-report.csv
Property Name: data ← binary property to write
The directory must already exist — n8n will not create intermediate directories.
Convert to/from File
This node doesn't touch the disk. It converts:
-
To File: Takes text/JSON data from an item and converts it into a binary file object (e.g., turn a JSON object into a downloadable
.jsonfile or a string into a.txtfile). - From File: Takes a binary file object and extracts its content into text or JSON item data.
Convert to File — Operation modes
| Mode | Input | Output binary |
|---|---|---|
| Move Base64 String to File | Base64 string field | Binary property |
| Move Item Data to JSON File | Entire item |
.json binary |
| Move Item List to CSV | Array of items |
.csv binary |
Convert from File — Operation modes
| Mode | Input binary | Output |
|---|---|---|
| Extract From ICS |
.ics calendar file |
Calendar event fields |
| Extract From JSON |
.json binary |
Parsed JSON item |
| Extract From ODS/XLS/XLSX | Spreadsheet binary | Row items |
| Extract From PDF | PDF binary | Text + metadata |
| Move Binary Data to Item | Any binary | Base64 string field on item |
Credential Setup
None required. Both nodes use the n8n process's filesystem permissions. Make sure:
- The n8n process user has read/write access to the paths you use.
- Your
docker-compose.ymlor systemd config mounts the correct volumes.
Docker volume mount example:
volumes:
- /home/user/n8n-files:/data
Then reference /data/output/report.csv in the node, not the host path.
Common Gotchas
| Gotcha | Fix |
|---|---|
| Directory doesn't exist | Create it manually or add an Execute Command node to mkdir -p /data/output before the write |
| Permission denied | Check that the n8n user owns the directory; in Docker, set user: "1000:1000" in compose |
| File path with spaces | Wrap in quotes in shell commands; n8n handles it fine in node fields |
| Reading a file that doesn't exist | Wrap in an Error Trigger or use Continue On Fail to handle gracefully |
| Writing overwrites silently | n8n does not warn — use a timestamp in the filename to avoid collisions |
| Large files crash execution | Stream large files in chunks using Execute Command + split; n8n loads entire file into memory |
| Cloud users getting "node not available" | Read/Write Files is self-hosted only; use S3/Drive instead |
| Binary property name mismatch | The property name in Read must match the name consumed by the next node (e.g., EmailSend expects attachment) |
Three Production Patterns
Pattern 1: Daily CSV Report — Write to Disk
Trigger → fetch data from DB/API → Convert to File (CSV) → Write File to Disk → Email attachment.
{
"name": "Daily CSV Report to Disk",
"nodes": [
{
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"parameters": {
"rule": { "interval": [{ "field": "cronExpression", "expression": "0 7 * * *" }] }
},
"position": [0, 0]
},
{
"name": "Fetch Data",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"url": "https://api.example.com/sales/today",
"responseFormat": "json"
},
"position": [200, 0]
},
{
"name": "Convert to CSV",
"type": "n8n-nodes-base.convertToFile",
"parameters": {
"operation": "csv",
"binaryPropertyName": "report"
},
"position": [400, 0]
},
{
"name": "Write to Disk",
"type": "n8n-nodes-base.readWriteFile",
"parameters": {
"operation": "write",
"fileName": "/data/reports/sales-{{ $now.format('yyyy-MM-dd') }}.csv",
"dataPropertyName": "report"
},
"position": [600, 0]
}
]
}
Pattern 2: Process Incoming Files — Read, Parse, Store
Watch directory → Read file → Convert from File (CSV/JSON) → Upsert to DB → Archive file.
Use case: a partner drops a CSV into /data/incoming/ each night; your workflow reads, parses rows, and upserts them to Postgres.
Schedule Trigger (every 5 min)
→ Execute Command: ls /data/incoming/*.csv
→ IF: stdout not empty
→ Read File from Disk: /data/incoming/{{ $json.filename }}
→ Convert from File: Extract From CSV (or JSON)
→ Postgres: Upsert rows
→ Execute Command: mv /data/incoming/{{ $json.filename }} /data/archive/
Pattern 3: PDF Ingestion Pipeline
HTTP webhook receives a PDF upload → Save to disk → Extract text → Send to AI → Store result.
Webhook (receives binary PDF)
→ Write File to Disk: /data/pdfs/{{ $now.toMillis() }}.pdf
→ Convert from File: Extract From PDF
→ OpenAI / Claude: Summarize extracted text
→ Airtable: Store summary + source filename
This keeps the raw PDF on disk for audit while routing the extracted text through your AI pipeline.
Free Workflow JSON
Here's the daily CSV report pattern as importable JSON — paste into n8n → Import from JSON:
{
"name": "op: Daily CSV Report Writer",
"nodes": [
{
"parameters": {
"rule": {
"interval": [{ "field": "cronExpression", "expression": "0 7 * * 1-5" }]
}
},
"name": "Every Weekday 7am",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.1,
"position": [240, 300],
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
},
{
"parameters": {
"url": "https://httpbin.org/json",
"options": {}
},
"name": "Fetch Sample Data",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [460, 300],
"id": "b2c3d4e5-f6a7-8901-bcde-f12345678901"
},
{
"parameters": {
"operation": "csv",
"binaryPropertyName": "report",
"options": {}
},
"name": "Convert to CSV",
"type": "n8n-nodes-base.convertToFile",
"typeVersion": 1,
"position": [680, 300],
"id": "c3d4e5f6-a7b8-9012-cdef-123456789012"
},
{
"parameters": {
"operation": "write",
"fileName": "=/data/reports/report-{{ $now.format('yyyy-MM-dd') }}.csv",
"dataPropertyName": "report",
"options": {}
},
"name": "Write to Disk",
"type": "n8n-nodes-base.readWriteFile",
"typeVersion": 1,
"position": [900, 300],
"id": "d4e5f6a7-b8c9-0123-defa-234567890123"
}
],
"connections": {
"Every Weekday 7am": { "main": [[{ "node": "Fetch Sample Data", "type": "main", "index": 0 }]] },
"Fetch Sample Data": { "main": [[{ "node": "Convert to CSV", "type": "main", "index": 0 }]] },
"Convert to CSV": { "main": [[{ "node": "Write to Disk", "type": "main", "index": 0 }]] }
}
}
Key Takeaways
- Read/Write Files from Disk is self-hosted only — cloud users need S3/Drive
- Convert to/from File handles format conversion (CSV, JSON, PDF, XLSX) without touching the disk
- Always pre-create directories; n8n won't make them for you
- Use timestamps in filenames to avoid silent overwrites
- For large files, stream via Execute Command rather than loading fully into memory
Want a complete n8n automation toolkit? The n8n Workflow Starter Pack ($29) includes 10 production-ready workflow JSONs for the most common automation patterns — lead capture, Stripe fulfillment, error monitoring, and more. Import and run in minutes.
Top comments (1)
Are you running n8n self-hosted and using the Read/Write Files node in production? Would love to hear what directory setups people are using — CSV exports, incoming webhook file drops, or PDF ingestion pipelines.