How to Fix n8n Running Out of Memory on Large Video Files

Your n8n workflow runs fine on a 40 MB test clip and dies on the real 1.2 GB export. The execution stops mid-node, the container restarts, and the log says JavaScript heap out of memory with nothing useful after it. This is a different failure from the 30-second HTTP timeout, and turning the timeout up will not help you.
Quick answer: n8n runs out of memory on large video files because n8n holds binary data in the execution's memory, so a 1 GB file loaded by the Read/Write Files from Disk node pushes the Node.js process past its heap limit and kills the instance. SettingN8N_DEFAULT_BINARY_DATA_MODE=filesystemand raisingNODE_OPTIONS=--max-old-space-size=4096buys headroom on self-hosted n8n. The fix that actually holds is to keep the bytes out of n8n entirely: send a file URL to a video processing API like FFmpeg Micro, poll the job, and pass the returned output URL to the next node.
Why n8n runs out of memory on large video files
Conventional wisdom says n8n needs a bigger box. Most instances do crash less when you throw RAM at them. But the cause isn't the size of your server, it's n8n's data model: every item flowing between nodes carries its binary payload with it, and in the default binary data mode that payload lives in the Node.js heap for the whole execution.
That matters more than it sounds. n8n passes item data forward rather than handing off a stream, so a 1 GB video can exist as more than one live buffer at once while a node runs. When execution data gets persisted, binary is serialized as base64, which adds roughly 33% on top of the original size. A 1 GB MP4 becomes about 1.37 GB of string before anything else happens.
Node.js has a hard ceiling here. The V8 old-space limit on a default 64-bit install lands in the low gigabytes, so the process doesn't degrade gracefully, it aborts. In Docker you'll see the container exit with code 137, which is the kernel OOM killer, not an n8n bug.
The node that kills the instance is Read/Write Files from Disk
Read/Write Files from Disk (still called Read Binary File in older workflows) reads the entire file into a buffer before it emits an item. There's no streaming mode. Point it at an FFmpeg output sitting in /data/renders/final.mp4 and n8n will try to materialize the whole thing in memory in one shot.
An n8n community thread describes this exactly: a builder with a roughly 1 GB video bound for YouTube found that Read File from Disk caused memory issues on the instance (community.n8n.io thread 121280). Other threads in the same forum show people trying to get FFmpeg working on n8n Cloud at all and hitting a wall from the other direction.
The old escape hatch is gone too. The Execute Command node is disabled by default in n8n v2.0 because arbitrary shell execution is a security problem on shared instances, so "just shell out to FFmpeg and read the file back" is no longer a setup most builders can reach for.
The settings that buy headroom, and where they stop
Three environment variables genuinely help on self-hosted n8n, and it's worth setting them before you re-architect anything.
N8N_DEFAULT_BINARY_DATA_MODE=filesystemstores binary payloads on disk and passes a reference between nodes instead of the buffer.NODE_OPTIONS=--max-old-space-size=4096raises the V8 heap ceiling to 4 GB so a single large buffer doesn't abort the process.EXECUTIONS_DATA_SAVE_ON_SUCCESS=nonestops n8n from writing full execution payloads to the database on every successful run.
Filesystem mode is the one people expect to solve everything, and it doesn't. It changes where binary data rests between nodes. Any node that has to actually work on the bytes still pulls them into memory: Read/Write Files from Disk, HTTP Request when uploading a file body, the YouTube node, the Google Drive node. So filesystem mode turns "crashes at 400 MB" into "crashes at 1.5 GB," which is a delay, not a fix. And on n8n Cloud you can't set NODE_OPTIONS at all.
Pass URLs through n8n, never bytes
The version of this workflow that survives a 4 GB source file moves zero video bytes through n8n. The file lives in object storage, n8n sends a URL to a processing API, and the API returns another URL. n8n only ever holds JSON of a few hundred bytes.
Compare what you'd run locally with what the workflow sends. The direct FFmpeg route for a 1 GB source looks like this:
ffmpeg -i input.mov -vf scale=-2:1080 -c:v libx264 -crf 23 -preset medium \
-c:a aac -b:a 128k output.mp4
That command is correct and it works. It also needs FFmpeg installed, a machine with disk and CPU to spare, a way to get the file onto that machine, and a way to get the result back. The API equivalent is one request that references the file where it already sits:
curl -X POST https://api.ffmpeg-micro.com/v1/transcodes \
-H "Authorization: Bearer $FFMPEG_MICRO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"inputs": [{ "url": "https://storage.example.com/raw/interview.mov" }],
"outputFormat": "mp4"
}'
In n8n, that's an HTTP Request node with the JSON body above, then a Wait node, then a second HTTP Request node hitting GET https://api.ffmpeg-micro.com/v1/transcodes/{{ $json.jobId }} on a 5 to 10 second interval. When the job settles, the response carries the output location:
{
"success": true,
"jobId": "job_9f2c4b",
"status": "completed",
"outputUrl": "https://storage.ffmpeg-micro.com/out/job_9f2c4b.mp4",
"createdAt": "2026-08-19T14:02:11Z",
"completedAt": "2026-08-19T14:03:48Z"
}
Branch on status with an IF node: completed goes to your publish step, failed goes to a Slack alert or a retry. Peak n8n memory for that entire chain is the size of that JSON. If you're wiring this into a repurposing or publishing pipeline, the social media automation page shows the same shape end to end, and the FFmpeg Micro docs cover the job lifecycle and the polling contract. There's a free tier, so you can test the whole path on a real 1 GB file before changing anything in production.
The difference is easier to see side by side:
| Bytes through n8n | URLs through n8n | |
|---|---|---|
| What the source node emits | 1 GB binary item | JSON with a URL |
| Peak n8n heap | 1.4 GB and up | under 1 MB |
| Where processing runs | your n8n container's CPU | the API's workers |
| Failure at 1 GB | heap abort, exit 137 | none |
| Recovery after a crash | re-download and redo | job id is still valid |
Common pitfalls when you rework the workflow
Most people get halfway to the URL pattern and leave one node that still swallows the file. These are the ones that keep instances dying after a "fix."
- Loop Over Items with a batch of videos. Ten items each carrying a 200 MB buffer is 2 GB of heap, even though no single file is large. Batch size 1, and pass URLs.
- HTTP Request set to download the file "just to check it." A HEAD request or the API's job status gives you the size and duration without pulling the body.
- Saving execution data on success. With binary attached, every successful run writes a base64 blob to your database. Postgres will grow faster than the videos do.
- The final upload hop. YouTube's resumable upload API needs the actual bytes, so one download-then-upload is unavoidable for that step. Do it last, do it on the processed output rather than the 1 GB source, and keep nothing else in the execution. A 1080p re-encode of a 1 GB source is often 150 to 250 MB, which n8n handles without complaint.
When passing URLs is the wrong call
Keeping bytes out of n8n assumes your files are reachable over HTTP. If the source video only exists on a laptop, an internal NAS, or a private bucket with no signed-URL support, a processing API can't fetch it, and you need an upload step somewhere regardless. Generate a signed URL from S3, Google Cloud Storage, or Cloudflare R2 first, then the pattern applies again.
It's also the wrong shape if your job is sub-second and trivial, like reading a duration or a codec from metadata. A network round trip plus polling costs more wall-clock time than doing it inline. And if you need frame-accurate interactive editing with a timeline and previews, that's a video editor's job, not an API's. FFmpeg Micro is an API, so it fits the pipeline steps, not the creative pass.
For the workflow patterns around this one, the n8n video automation walkthrough builds the clip pipeline end to end, Make.com's file size limit isn't your video covers the identical failure on Make, and Google Sheets is a fine video processing queue with n8n shows how to track job ids across runs.
FAQ
Why does n8n run out of memory on large video files?
n8n keeps binary data in the execution's memory by default, so a large video file exists as a live buffer in the Node.js heap while nodes run. Once the total passes the V8 old-space limit, the process aborts with JavaScript heap out of memory, and in Docker the container exits with code 137.
Does N8N_DEFAULT_BINARY_DATA_MODE=filesystem fix video memory errors?
Filesystem mode helps but doesn't solve it. The setting stores binary payloads on disk and passes references between nodes, which cuts idle memory a lot, but any node that operates on the bytes (Read/Write Files from Disk, YouTube, Google Drive, HTTP Request with a file body) still loads the full file into memory when it runs.
What's the largest video file n8n can handle?
There's no fixed n8n limit, only the Node.js heap ceiling and your container's RAM. Self-hosted n8n with --max-old-space-size=4096 and filesystem mode handles files in the hundreds of megabytes reliably; past about 1 GB the failures start showing up regardless of settings. Passing URLs removes the ceiling because the file size stops being n8n's problem.
Can I still run FFmpeg inside n8n?
Running FFmpeg inside n8n is much harder than it used to be. The Execute Command node is disabled by default in n8n v2.0 for security reasons, it never existed on n8n Cloud, and even when you enable it on a self-hosted instance you still have to read the output file back through a node that buffers it in memory.
How do I upload a large video to YouTube from n8n without crashing it?
Process the video through an API first so the file that reaches n8n is a compressed output rather than the raw source, then fetch that output URL directly into the YouTube node as the last step of the workflow. Shrinking a 1 GB source to a 200 MB 1080p MP4 before the upload hop is usually the whole fix.
If you want to try the URL-passing version on the file that's currently killing your instance, sign up free and point a transcode job at it. The first request takes about two minutes to wire into an HTTP Request node.
About Javid Jamae
Founder & CEO at FFmpeg Micro
Javid is a software engineer, author, and entrepreneur with over 25 years of professional software development experience across enterprise, startup, and consulting environments. He founded FFmpeg Micro to make video processing accessible to developers through a simple, automation-first REST API.
You might also like

Clip, Caption, and Reformat Video in One n8n Workflow API Chain
Clip, caption, and reformat video in one n8n workflow: three chained FFmpeg Micro API jobs, so n8n passes URLs, never video bytes, with no servers to run.

FFmpeg Scene Detection: Auto-Split a Long Video at Scene Changes
FFmpeg scene detection with select='gt(scene,0.4)',showinfo finds cut points automatically, then split a long video into clips by scene, no hand-marked timestamps.

Turn long-form video into Shorts/Reels/TikToks automatically
Turn long form video into shorts automatically by splitting moment-picking from clip-making, then calling a video API to cut, crop to 9:16, and caption.
Ready to process videos at scale?
Start using FFmpeg Micro's simple API today. No infrastructure required.
Get Started Free