Skip to content
All articles
Automation & AI

Where low-code ends: video processing in an n8n project

Andrey Gershengoren · · 5 min

n8n is a good tool as long as the task fits the nodes it ships with. It gets interesting where the task stops fitting. In a video project I hit that point, and it caught me out. What decided the matter was what the task demanded of the environment, and the logic behind it stayed simple throughout. This post describes the case and the decision that followed from it.

The starting position

For a news platform on Telegram I built a pipeline that turns text messages into videos: an avatar presenter reads the message out. Orchestration ran in n8n on a managed instance, video generation through an external API.

The problem came after that. The generated videos had to be brought to a uniform format, and cropping alone was not enough. The presenter had to stay centred in frame after the crop, wherever their face happened to sit in the source video. That makes the crop region depend on the content of the video, so it cannot be fixed in advance as a constant.

Why not in n8n

On a self-hosted instance, ffmpeg is reachable through Execute Command or a Code node. On the managed instance that route was closed: no binaries of my own, no access to the environment's file system.

Even setting that aside, n8n would have been the wrong place. Video processing is a long-running, CPU-intensive job. A workflow engine is not built for it: timeouts, no meaningful testability, no control over resources.

This is where the limit of low-code runs: at the demands placed on the runtime, not at the complexity of the logic. A workflow may branch, distinguish cases and connect services, as long as each individual step is short and cheap. Once a step runs for minutes and saturates a CPU, you can still express it in the workflow, but the environment was never built for that kind of work.

The decision

The project already included a Strapi backend on a VPS. I added an endpoint there that takes a video, processes it, and returns it. n8n calls that endpoint as one step in the workflow.

The processing itself has three parts. ffmpeg was added to the Docker image as a system package. fluent-ffmpeg comes in as the Node wrapper; the library does not replace ffmpeg, it spawns it as a child process. The gain is ergonomic: a readable API instead of hand-built argument strings, events for progress and errors. face-api.js handles face detection. The crop region is computed from the position of the face, so the presenter ends up centred in the target format.

There was a self-contained alternative: a separate worker with a queue. I rejected it. The platform's volume did not justify additional infrastructure with its own deployment and its own monitoring. The existing backend process was the right place for this job, at that time, at that volume.

The qualifier at the end is not filler. It is the condition under which the decision holds.

The price of the decision

What I bought was simplicity: no new infrastructure, one deployment instead of two, a solution in days rather than weeks. What I paid with was coupling.

Video processing and the CMS share a process, which makes load on one side load on the other. Every change to the video logic means deploying the whole backend. And there is no fault isolation: a malformed input file that crashes the ffmpeg process does not endanger a video service, it endangers the backend.

The last point is the uncomfortable one, because it lands on the editorial side rather than the technical one. A video that fails to render is a story that did not go out. A backend that goes down with it is a platform that did not go out. These risks were known and accepted deliberately.

The limit

The solution holds as long as two conditions do: a Node backend already exists, and the processing volume stays small enough not to compete with the backend's main load. If either falls away, it was the wrong decision, and wrong retroactively.

If the volume grows past that, the next step is clear: move the processing into a separate worker with a queue. The endpoint interface stays as it is, which bounds the rebuild. The call from n8n does not know who answers on the other side, and does not need to. That leaves the rejected path deferred rather than discarded.

A conductor, not an orchestra

For the low-code context the lesson is: n8n orchestrates, it does not compute. This is the same boundary I have described elsewhere as the limit of responsibility, seen from the other side. There it was about logic growing too large for a function node. Here it is about work growing too heavy for the environment.

Anyone who can write code treats the workflow engine as what it is: a conductor, not an orchestra.

n8nautomationffmpegarchitecturelow-code
Contact

First conversation: 30 minutes, free of charge, no presentation.

You describe the situation, I tell you whether and how I can help. No slides, no sales pitch.