FlowKit

n8n Read/Write Files from Disk node: reading and writing files

Published 25 August 2026 · 7 min read

A folder dropped by a scanner, a CSV export to produce before an SFTP transfer, a log file to append to: all of these assume a workflow can touch a real filesystem. In n8n, that's the job of the Read/Write Files from Disk node (n8n-nodes-base.readWriteFile). Its defining trait — and the source of nearly every problem people hit with it — fits in one sentence: it acts on the disk of the machine running n8n, not on remote storage. This guide covers its two operations, what Docker actually changes, and how to avoid ENOENT errors, EACCES errors, and files that vanish on redeploy.

Two operations, one disk

The node exposes exactly two operations, with no credential to configure since there's no connection to establish:

Operation What it does
Read File(s) From Disk Retrieves one or more files from the machine hosting n8n and attaches them as binary data on the output items
Write File to Disk Writes an item's binary field to a file, on that same machine

That "same machine" is the key to everything else. Unlike the SFTP node or a cloud storage node, Read/Write Files from Disk doesn't cross the network: the path you type is interpreted from the n8n process's point of view. On a bare server, that's the server's disk. In Docker — the dominant install method since our installation guide — it's the container's filesystem, which is not at all the same thing as the host's.

Read File(s) From Disk: the glob pattern changes everything

The main parameter is called File(s) Selector. It accepts a plain path (/files/report.pdf) but also glob patterns: * for one segment, ** for a recursive descent, ? for a single character, [] for a set. /files/incoming/*.pdf picks up every PDF in a folder; /files/**/*.csv walks the whole tree.

Each matched file produces one item, with the content placed in a binary field. The Options let you tune that behaviour:

  • Put Output File in Field — the name of the output binary field (data by default). Useful when a downstream node expects a specific name.
  • File Name, File Extension, MIME Type — force the metadata attached to the binary instead of letting n8n infer it from the path. Essential when the source produces extension-less or mistyped files.

The recursive-glob trap is worth flagging: ** on a deep folder can return thousands of items in a single execution, all loaded at once. If the volume is uncertain, tighten the pattern, or switch binary storage to filesystem mode as explained in our guide to large files and n8n memory — this is exactly the scenario that ends in JavaScript heap out of memory.

Write File to Disk: two parameters, one option that matters

On the write side, two parameters are enough: File Path and Name, the full destination path including the extension, and Input Binary Field, the name of the binary field to write. The node writes binary data, so to produce a CSV or JSON file you first convert your data with the Convert to File node, then hand the resulting binary to Write File to Disk.

The single option, Append, decides whether the node overwrites the file or adds to the existing content. That's what separates an export regenerated on every run from a log file that accumulates across runs. Two habits prevent most write failures: use an absolute path, and make sure the parent folder already exists — the node writes a file, it doesn't build a directory tree for you.

Cloud vs self-hosted: the real dividing line

On n8n Cloud, the node can only access paths under /home/node/, and the filesystem offers no persistence guarantee from one execution to the next: scratch space, never storage. To keep anything produced on Cloud, you have to push it out to S3, Drive or SFTP.

On self-hosted, the node reaches whatever the n8n process can reach by default — its strength and its risk. Worth noting before an upgrade: starting with n8n 2.0, N8N_RESTRICT_FILE_ACCESS_TO defaults to ~/.n8n-files. A workflow that read /srv/scans with no special configuration can therefore stop working after a version bump — one more item for the checklist in our Docker upgrade guide. This is one of the rare points where the self-hosted versus Cloud decision is settled in advance: if you need to read a network share, Cloud is out.

Docker: volumes, paths and the node user

In a standard Docker install, a named volume is mounted at /home/node/.n8n for the SQLite database and the encryption key. That volume isn't enough to handle business files: you have to explicitly mount the folder involved, for example -v /srv/scanner:/files. In the node, the path to enter is then /files/..., the container's view — never /srv/scanner/..., which only exists on the host.

The second friction point is process identity. The official image runs n8n as the node user, UID 1000. A host folder owned by root will be readable but not writable, producing EACCES errors that show up only on the write operation. The clean fix is to align ownership on the host (chown -R 1000:1000 /srv/exports) rather than switching the folder to 777.

The third point is the most expensive: a file written inside the container, outside a mounted volume, disappears on redeploy. A container's filesystem is a stack of layers optimised for distribution, not for persistence. The study Slacker: Fast Distribution with Lazy Docker Containers (Harter, Salmon, Liu, Arpaci-Dusseau & Arpaci-Dusseau, FAST 2016 — see it on Google Scholar) measured that trade-off across 57 containerised applications: pulling images accounts for 76% of container startup time, while only 6.4% of that data is ever read. The format is built to move an image fast and often, not to keep your exports safe. Hence the rule: every write path used by a workflow must map to a volume declared in docker-compose.yml, just like the instance's environment variables.

The most common errors

Symptom Likely cause Fix
ENOENT on read Path exists on the host but not in the container Mount the folder as a volume and use the container-side path
ENOENT on write Parent folder doesn't exist Create the folder upstream, or write to an already-mounted path
EACCES Folder owned by root, process running as UID 1000 chown -R 1000:1000 on the host folder
No output items, no error The glob pattern matches nothing Test the pattern, check extension and case
The written file is gone Written outside a volume, container recreated Write to a path backed by a volume
It worked before the upgrade N8N_RESTRICT_FILE_ACCESS_TO default in v2.0+ Declare the allowed directories explicitly

Restricting access: a genuine security surface

The node reads and writes with the n8n process's privileges: on a shared instance, anyone who can edit a workflow can read whatever n8n can read. Three guardrails exist. N8N_RESTRICT_FILE_ACCESS_TO limits access to a semicolon-separated list of directories; N8N_BLOCK_FILE_ACCESS_TO_N8N_FILES, true by default, blocks access to the .n8n directory and configuration files — and therefore to the credential encryption key; NODES_EXCLUDE lets you not load the node at all, with a value like ["n8n-nodes-base.readWriteFile"]. The same reasoning applies to the Execute Command node.

The most concrete danger is building a path from untrusted input. A File(s) Selector like /files/{{ $json.filename }}, fed by a public webhook or an attachment name, opens the door to directory traversal: one well-placed ../../ is enough to escape the intended folder. This isn't a theoretical risk — the study Eradicating the Unseen: Detecting, Exploiting, and Remediating a Path Traversal Vulnerability across GitHub (Akhoundali, Hamidi, Rietveld & Gadyatskaya, 2025 — see it on Google Scholar) identified 1,756 vulnerable open source projects sharing that same code pattern, with CVSS scores above 9.0, and only a 14% remediation rate after disclosure. The defence in n8n is the same as everywhere: never concatenate external input straight into a path, validate the filename against an allowlist or a strict regular expression in a Code node, and confine access to a dedicated directory.

Four use cases that justify this node

Processing a folder dropped by a scanner or a network share. A Schedule Trigger, a Read File(s) From Disk on /files/incoming/*.pdf, then a pipeline for automatically classifying incoming documents. It's the most common scenario, and the one where mounting a volume is non-negotiable.

Producing an export before transfer. Convert to File to generate the CSV, Write File to Disk to drop it on disk, then an SFTP node to ship it. Going through disk keeps a local copy of exactly what was sent.

Feeding a log file or an audit trail. The Append option turns the node into an application log: one line per execution, in a flat file any ops tool can read.

Caching a large binary outside memory. Writing an archive to disk, processing it in chunks, then compressing or extracting it avoids holding several hundred MB in the process for the whole execution.

Going further

Read/Write Files from Disk is a simple node whose entire difficulty lies elsewhere: in your deployment topology. Once volumes and permissions are set up correctly, it becomes the most reliable building block of a document pipeline — it's the foundation for the attachment triage in the AI Inbox Pack ($79) when files arrive through a shared folder rather than by email, and for a file-level audit trail in the Compliance & Audit Pack ($149), where every processed document leaves a written trace on a dedicated volume, backed up along with the rest of the instance.

FAQ

Frequently asked questions

Does the Read/Write Files from Disk node work on n8n Cloud?

It exists there, but under tight constraints: on n8n Cloud the node can only access paths under /home/node/, and the filesystem offers no persistence guarantee between executions. In other words, it can serve as a scratch area inside a single execution, never as durable storage. To keep a file produced on n8n Cloud, you have to push it to external storage: S3, Google Drive, SFTP.

Why do I get an ENOENT error when the file clearly exists?

Nine times out of ten the path is correct on the host machine but not inside the n8n container. The node reads the container's filesystem: if /srv/scans isn't mounted as a volume, it simply doesn't exist as far as n8n is concerned. Check the mount with docker inspect, use the path as seen from inside the container, and prefer absolute paths over relative ones, whose base depends on the process working directory.

How do I fix an EACCES error when writing files with n8n in Docker?

EACCES is a permissions problem, not a path problem. The official Docker image runs n8n as the node user (UID 1000): if the mounted folder is owned by root, writes are refused. The usual fix is to hand the folder to UID 1000 on the host, for example chown -R 1000:1000 /srv/exports, rather than opening it up with 777.

How do I stop users on a shared instance from reading arbitrary files?

There are two levers. N8N_RESTRICT_FILE_ACCESS_TO limits access to a semicolon-separated list of directories, and N8N_BLOCK_FILE_ACCESS_TO_N8N_FILES (true by default) blocks access to the .n8n directory and user-defined configuration files. If the node isn't needed at all, the simplest option is not to load it, via NODES_EXCLUDE with a value such as ["n8n-nodes-base.readWriteFile"].

Bundle FlowKit Complet

€269