n8n 3.0 breaking changes kill your FFmpeg step. Send it HTTP.

Your n8n box runs npx n8n, your Execute Command node shells out to the ffmpeg you installed on the host two years ago, and v3 is scheduled for this month. Three items on the 3.0 breaking-changes list land on that one workflow. Every migration guide walks you to Docker and never says the word ffmpeg, so you can follow all of it and still end up with a dead video step.
Quick answer: The n8n 3.0 breaking changes that kill a self-hosted FFmpeg step are Docker-only self-hosting (npm and npx installs are discontinued), the rename of~/.n8n/binaryDatato~/.n8n/storage, and the end of in-memory binary data mode. To keep running FFmpeg yourself, move to Docker Compose and copy staticffmpegandffprobebinaries into the image with a multi-stage build, because the official n8n image is distroless andapk add ffmpegfails. If you'd rather not own a media binary across major versions, swap the Execute Command node for an HTTP Request to a hosted FFmpeg API such as FFmpeg Micro: no install to migrate, and the job survives the upgrade untouched.
What n8n 3.0 removes that a video workflow depends on
The v3.0 breaking changes page puts the release in October 2026. Four of the removals stack onto one media workflow, which is why no upgrade checklist catches all of them.
| 3.0 change | What it does to a video step |
|---|---|
| Docker-only self-hosting; [npm and npx installs discontinued](https://docs.n8n.io/deploy/host-n8n/install-options/install-with-npm) | The host `ffmpeg` on your PATH is no longer on the container's PATH |
| `~/.n8n/binaryData` renamed to `~/.n8n/storage` | Any workflow or script with a hard-coded path breaks; n8n refuses to start if both directories exist |
| `N8N_DEFAULT_BINARY_DATA_MODE=default` (in-memory) no longer valid | Instances fall back to filesystem mode, so every frame of a 1 GB clip goes through disk |
| `N8N_RUNNERS_TASK_TIMEOUT` default drops from 300s to 60s | A three-minute transcode now gets killed at one minute |
Two more are worth a grep. Read Binary File, Read Binary Files and Write Binary File are removed in favor of Read/Write Files from Disk, the trio self-hosters use to shuttle a video to disk, run FFmpeg, and read the output back. N8N_UNVERIFIED_PACKAGES_ENABLED also flips to false, so the FFmpeg community node you installed from npm stops loading.
n8n 2.x ships a Migration Report under Settings for global admins on 1.119.0 and later. Run it. It reads workflow JSON, so it flags affected nodes and env vars but can't see a host binary called through Execute Command or a four-minute encode.
Failure mode 1: npx n8n plus a host ffmpeg
The npx install disappears outright, and with it the assumption that your workflow and your encoder share a filesystem. Running n8n in a container doesn't move ffmpeg into it. You have to build it in.
First, copy ~/.n8n/config somewhere safe. It holds the encryption key for your credentials, and a fresh container generates a new one, so every stored credential becomes undecryptable.
The official image, docker.n8n.io/n8nio/n8n, went distroless in 2026: the package manager is gone, so the USER root; RUN apk add --no-cache ffmpeg line in older tutorials fails. Copy static binaries in from another stage:
FROM mwader/static-ffmpeg:7.1 AS ffmpeg
FROM alpine:3.20 AS fonts
RUN apk add --no-cache fontconfig ttf-dejavu font-noto-emoji
FROM docker.n8n.io/n8nio/n8n:2.43.0
USER root
COPY --from=ffmpeg /ffmpeg /usr/local/bin/ffmpeg
COPY --from=ffmpeg /ffprobe /usr/local/bin/ffprobe
# ffmpeg is statically linked, but fonts are data it loads at runtime
COPY --from=fonts /etc/fonts /etc/fonts
COPY --from=fonts /usr/share/fonts /usr/share/fonts
USER node
Those last two COPY lines are the ones people skip. The static build has freetype compiled in, but it still has to find a font file on disk. Without /etc/fonts and a real family installed, drawtext fails with "Cannot find a valid font" and subtitles= burn-in renders empty boxes. That's an encode-time failure, so the image looks fine until a caption job runs.
The Compose file is short:
services:
n8n:
build: .
ports:
- "5678:5678"
environment:
- N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
- NODES_EXCLUDE=[]
- N8N_RUNNERS_TASK_TIMEOUT=300
volumes:
- n8n_data:/home/node/.n8n
volumes:
n8n_data:
NODES_EXCLUDE=[] is doing real work there. Execute Command has been disabled by default since n8n 2.0.0, as the RxChi1d/n8n-ffmpeg image documents, and an empty exclude list turns arbitrary shell execution back on for everyone with editor access. Fine on a single-user box, bad on a shared team instance. We wrote up the alternative when that default landed: n8n disabled the Execute Command node, your FFmpeg needs HTTP.
Failure mode 2: workflows with a hard-coded binaryData path
On first start, 3.0 renames ~/.n8n/binaryData to ~/.n8n/storage, removes N8N_MIGRATE_FS_STORAGE_PATH, and refuses to start if both directories exist. N8N_STORAGE_PATH keeps the old location if the path has to stay put.
The rename bites workflows that reach into that directory themselves, which media workflows do constantly: a Code node building /home/node/.n8n/binaryData/input.mp4 for ffmpeg, an Execute Command string with the path inlined, a cleanup cron on the host. Find them first:
grep -rln 'binaryData' ~/.n8n/ ./workflows/*.json
Then check whether a half-finished earlier migration left both directories on the volume. That one stops the container booting, and the error points at directories, not your video step, so it reads like an unrelated storage problem.
Failure mode 3: large videos that leaned on in-memory binary passing
Losing in-memory binary mode changes the physics of a large-file workflow, not just its configuration. If you never set N8N_DEFAULT_BINARY_DATA_MODE, you were on default, which held binary data in memory between nodes. That value is invalid in 3.0, so the instance switches to filesystem and a 1 GB clip gets written to and read from the volume at every hand-off.
Your volume needs headroom you never had to size before, including room for the intermediates a multi-step encode leaves behind. Filesystem mode is also unsupported with queue mode, so a scaled instance has to move binary storage to database or S3. The decompression cap drops from 2 GiB to 256 MiB, which matters if a step unzips a batch of source clips.
The cleanest fix is architectural: stop routing bytes through n8n. Pass a URL into the processing step, let the processor fetch and write the file, and take a webhook or a poll back with the output URL. n8n moves JSON, not gigabytes, and no storage-mode change touches it. We walked through that pattern for a related failure in large video transcription in n8n fails, send a URL not the file.
The version of this that has nothing to migrate
Look at the sequence rather than n8n 3.0 alone. Execute Command was disabled by default in 2.0. The official image went distroless in 2026 and broke every published install recipe. n8n's community installer strips optionalDependencies, so a community node shipping bundled FFmpeg builds silently delivered no binary and failed with "No usable ffmpeg was found." Now 3.0 takes npx, the storage path, in-memory mode, and 240 seconds of runner timeout. The binary is the part that keeps breaking.
An HTTP Request node has no install to migrate. The same node JSON that ran on 1.x runs on 3.0, because the encoder isn't in your container and the output never has to come back off your disk. Manual step and hosted step, side by side:
# In the container you now maintain
ffmpeg -i /home/node/.n8n/storage/input.mp4 \
-c:v libx264 -crf 23 -vf scale=-2:1080 output.mp4
# From an HTTP Request node, no binary anywhere in your stack
curl -X POST https://api.ffmpeg-micro.com/v1/transcodes \
-H "Authorization: Bearer $FFMPEG_MICRO_KEY" \
-H "Content-Type: application/json" \
-d '{
"inputs": [{ "url": "gs://your-bucket/1234567890-input.mp4" }],
"outputFormat": "mp4",
"preset": { "quality": "medium", "resolution": "1080p" }
}'
The response comes back immediately with {"id": "job-uuid", "status": "pending"}. Poll GET /v1/transcodes/{id} until it reads completed, then GET /v1/transcodes/{id}/download for a signed URL. The job runs on our side, so a three-minute transcode isn't a three-minute node execution, which is why the 60-second runner timeout stops being your problem. Over 700 developers and automation builders use FFmpeg Micro, more than 300 of them from Make or n8n. The quickstart has the full upload-confirm-transcode-poll-download flow in curl, Node, and Python.
Cost: one token buys 10 seconds of input video, metered per second with no rounding up to the minute. A new account gets 200 tokens free, around 33 minutes of video, no card. Trim a 30-second clip out of a one-hour recording and you're billed for 30 seconds. Failed jobs are never billed. Starter is $19.99 a month for 2,500 tokens.
When keeping ffmpeg in your own image is still right
Owning the binary makes sense in a few cases. If your source files never leave the building, an outbound API is a non-starter, so budget for the Dockerfile. If you need -filter_complex graphs, hardware encoders, or a codec outside the common set, a managed API will constrain you; FFmpeg Micro doesn't support -filter_complex. And if your inputs routinely exceed the input cap (100 MB on Free, 1,024 MB on Starter, 2,048 MB on Pro), local processing wins on size alone.
What you accept in exchange is a standing maintenance job. Community n8n+FFmpeg images poll upstream every six hours and rebuild, because each n8n release can move the base image, the user, or the paths your COPY lines depend on. If you'd rather not re-verify a Dockerfile on someone else's schedule, we covered the no-image route in how to use FFmpeg in n8n without touching your Docker image.
Pitfalls that bite during the upgrade
Most of these show up after the container starts, which makes them hard to attribute:
apk add ffmpegfails on the distroless image; copy static binaries in a multi-stage build.- No
/etc/fontsor font package breaksdrawtextand subtitle burn-in at encode time. - Without
NODES_EXCLUDE=[], Execute Command refuses to run. - Both
~/.n8n/binaryDataand~/.n8n/storageon the volume stops n8n booting. - The 60-second runner timeout kills long encodes; raise
N8N_RUNNERS_TASK_TIMEOUT. - Queue mode plus filesystem binary storage is unsupported; use database or S3.
- Losing the key in
~/.n8n/configmakes stored credentials unreadable.
FAQ
When does n8n 3.0 actually ship?
n8n 3.0 hasn't shipped as of October 7, 2026, and the breaking-changes page says only that it's scheduled for October 2026. n8n's first conference, In The Loop, runs October 13 to 14, the likeliest spot for a confirmed date. Plan against the published list, not a rumor.
Does my Execute Command ffmpeg step survive the move to Docker?
An Execute Command step calling a host-installed ffmpeg doesn't survive the move to Docker by itself. The container has its own filesystem and PATH, so you build ffmpeg into the image and set NODES_EXCLUDE=[] to re-enable the node n8n 2.0.0 disabled. Both carry ongoing cost, which is why many builders switch to an HTTP call.
Will my community FFmpeg node still work after upgrading?
Community FFmpeg nodes that n8n hasn't verified stop loading in 3.0, because N8N_UNVERIFIED_PACKAGES_ENABLED flips from true to false by default. Set it back to true and the second problem shows up: n8n's installer strips optionalDependencies, so those nodes deliver no binary and fail with "No usable ffmpeg was found." They need a server-level FFmpeg install.
Can I test my workflows against 3.0 before upgrading?
Testing workflows ahead of the upgrade gets you partial coverage. The Migration Report in n8n 2.x (1.119.0 and later) flags removed nodes and instance env vars, and offline scanners that read workflow JSON catch removed node versions. None of them see a host binary called through Execute Command, a path built inside a Code node, or an encode that runs past the 60-second runner timeout.
If your upgrade window is still open and you'd rather the video step not be part of it, the quickstart creates a temporary API key and runs upload, transcode, poll, and download against your own file, before you pull the new image.
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

How to use FFmpeg in n8n without touching your Docker image
Most FFmpeg n8n Docker recipes break on n8n 2.x. Compare three working paths: the runners image plus fonts, a static-ffmpeg copy, and an HTTP call on Cloud.

Why n8n says "No usable ffmpeg was found" and what to do about it
"No usable ffmpeg was found" in n8n means the server has no FFmpeg binary, and n8n's installer makes it impossible for a community node to ship one. Three real fixes.

FFmpeg CVE-2026-96611: is your self-hosted build patched?
FFmpeg CVE-2026-96611 affects every build before 9.0. How to check the version your pipeline actually runs, who's exposed, and how to patch a container.
Ready to process videos at scale?
Start using FFmpeg Micro's simple API today. No infrastructure required.
Get Started Free