When a media automation should become code
A media automation should move from a visual canvas into code when a mistake in it costs more than the convenience of editing it without a developer. Branch count, loops carrying state across iterations, logic that needs test assertions and per-run cost at volume are the signals; the usual end state is a flow routing to one coded step.
The question is not whether the flow is complicated
Most teams frame the canvas-versus-code decision as a complexity question, and it is the wrong question. Plenty of complicated things live happily on a canvas, and plenty of three-block flows should never have been built there. The threshold that actually holds up is reviewability: when a mistake in the flow costs more than the convenience of editing it without a developer, it belongs in code.
That framing works because it names the trade the canvas is making. A visual automation earns its place by letting someone who does not write code change production behaviour in an afternoon. That is the whole value, and it is also the whole exposure. The same edit that took an afternoon took no review, produced no diff anyone else read, and ran against live assets the moment it was saved. As long as the worst outcome of a bad edit is cheap — a re-runnable tag, an alt-text field you can regenerate — the trade is a good one. The moment the worst outcome is expensive — an original deleted, a moderation gate that silently passed everything for a week — the convenience is being paid for in risk that nobody priced. The mechanics of getting a canvas under any kind of review at all are covered in version control for automations built on a visual canvas; this page is about deciding when review is no longer optional.
What follows weighs three positions against the same criteria: keep the automation on the canvas, rewrite it as a service, or split it. The criteria are the ones that actually predict trouble — branch count, loops with state, whether the logic needs tests, what each run costs against what a developer costs, and how badly the timing of the move can go wrong.
The three options
Stay on the canvas. For Cloudinary specifically that means MediaFlows, the visual automation product: PowerFlows (prebuilt automations for moderation, UGC deletion, multilingual alt text and CSV upload), EasyFlows, a block reference for building your own, and a Workflow Agent chat interface. Every flow is drivable from the MediaFlows MCP server as well, so an agent can create or edit the same automation a person would click together. The mechanism is an event — typically an upload into a product environment — followed by a sequence of blocks that inspect the asset and act on it. What it costs is platform pricing per run plus the ordinary credits any transformations consume. What you give up is everything code review gives you: a diff, a test, a reviewer’s sign-off before the change is live.
Rewrite as code. A service that receives the same event as a webhook, verifies it, and calls the Admin API to list, update, tag or delete resources. The mechanism is ordinary software: a handler, a queue if you need one, retries you wrote, tests you run before deploy. What it costs is a developer to build it and a developer to keep it working, plus hosting, plus the things the canvas gave you for free — the retry semantics, the operational dashboard, the fact that a non-developer could change it. The full trade between the two, from a first-build point of view, is worked through in a hosted visual automation against a hand-written webhook handler.
Split it. The flow keeps doing what a flow is good at — receiving the event, branching on a folder or a tag, routing an asset toward the right outcome — and one step, the one that needs real logic, is delegated to a service. This is the position most teams end up in whether they planned to or not, and the criteria below are largely about recognising which step is that step.
Criterion 1: branch count
Branch count is a decent proxy for the reviewability threshold, and it has the advantage of being countable. A flow with three branches is legible on a canvas: someone opening it cold can trace each path from the trigger to its terminal action and say what the automation does. A flow with fifteen branches is a program drawn badly. Every path still exists, but nobody holds them all in their head at once, the canvas scrolls, and the question ‘what happens to a video over 100 MB uploaded to this folder with no alt text’ is answered by clicking through blocks rather than by reading.
The mechanism behind the proxy is that a canvas has no abstraction. Code lets you name a decision once and call it from six places; a canvas makes you draw the decision six times, and the six copies drift. So branch count grows faster than the underlying logic does, and the point where the picture stops being clearer than the equivalent code arrives earlier than people expect.
Standing of each option: the prebuilt PowerFlows sit comfortably under the line — moderation is essentially one decision, UGC deletion is one decision with a schedule. An EasyFlow you built yourself starts there and grows. Code has no branch ceiling that matters at this scale. The split option is what you do when you notice that twelve of the fifteen branches are routing and three are logic: the twelve stay drawn, the three become a function.
Criterion 2: loops with state across iterations
Anything that needs a loop with state carried from one iteration to the next is already past the boundary. Visual tools express sequences well and iteration poorly, and this is structural, not a gap a better canvas closes. A sequence has a start and an end you can draw. A loop that has to remember what it did last time — a cursor into a paginated listing, a count of failures so far, the set of assets already touched in this pass — has state that lives between the blocks, and there is no block for that.
The canonical case is reconciliation. A per-event flow reacts to uploads; a reconciliation pass walks everything that exists, compares it against what should exist, and repairs the difference. Walking everything means paging through Admin API listings where each request depends on what the previous one returned, deciding per asset, and surviving being interrupted halfway. That is a program. It is worth noticing that this is also where rate limits bite: on the Free plan the Admin API allows 500 requests per hour (Cloudinary pricing, checked 2026-08-18), which a naive full listing of a large product environment will exhaust, so the loop needs to remember its position across hours as well as across iterations. Why the per-event flow leaves gaps in the first place, and how to schedule the pass that closes them, is the subject of reconciling what a per-event automation missed.
Standing of each option: the canvas is the wrong answer for anything with cross-iteration state, full stop; where a flow appears to loop it is usually re-triggering per event, which is fine precisely because each run is independent. Code is the right answer. The split option applies when the loop is one step in an otherwise sequential flow — the flow triggers on a schedule, calls the service that owns the loop, and routes the result.
Criterion 3: whether the logic needs assertions
Test coverage is the other signal, and it is the one engineers recognise fastest once it is named. Logic that needs assertions needs a test runner, and a canvas has nowhere to put one. If you find yourself wanting to write ‘given an asset with no alt field and a filename containing a slash, the flow must not …’, you have written a test case, and the canvas cannot hold it. You can run the flow against a sample asset and look at the result, and people do, but that is a manual check that evaporates the moment someone edits a block.
The mechanism is that assertions are about invariants — properties that must survive every future change — and a canvas has no notion of a future change. It has the current drawing. Code has the test suite that runs on every diff, which is exactly the review layer the reviewability threshold was asking for.
What ‘needs assertions’ looks like in a media automation: any transformation that has to be idempotent, because a re-run must not double-apply; any rule with named edge cases (empty metadata, unexpected format, an asset that already carries the tag); anything whose failure is silent rather than loud. Multilingual alt text is a good example of logic that mostly does not need assertions — the output is a field a human can eyeball and regenerate, and the multilingual alt text PowerFlow ships prebuilt because the failure mode is cheap. UGC deletion is the opposite: the PowerFlow exists and is useful, but the moment your deletion rule has a condition of your own in it, the absence of a test is the absence of the only thing standing between a typo and an unrecoverable loss.
Standing of each option: the canvas is fine for logic where a wrong run is visibly wrong and cheaply reversible. Code is required where a wrong run is quiet or irreversible. The split option puts exactly the assertable step behind an endpoint that has a test suite, and leaves the un-assertable routing on the canvas.
Criterion 4: cost, and where it flips
Cost flips too, and it flips in the direction people forget. Per-run platform pricing beats engineering time at low volume and loses at high volume, and the crossover is worth calculating rather than assuming, because the assumption usually runs the wrong way in both directions — engineers assume code is cheaper because they discount their own hours, and operations teams assume the platform is cheaper because the invoice is small this month.
The arithmetic is short. On the code side: hours to build, multiplied by a loaded rate, plus a monthly maintenance allowance (it is never zero), plus hosting. On the platform side: whatever your plan charges per run, multiplied by monthly runs. Both sides consume the same Cloudinary credits for the same transformations, storage and bandwidth — one credit is 1,000 transformations, or 1 GB stored, or 1 GB delivered (how credits are counted, checked 2026-08-18) — so credits cancel out of the comparison and you can leave them aside. The crossover in runs per month is the build-and-maintain cost divided by the per-run price the platform charges over what a run costs you in code. Put your own numbers in; the point is that it is a number and not a feeling. No per-run price is quoted here because none has been verified for this page; the figure to use is the one on your plan.
Standing of each option: below the crossover, the canvas wins on cost and there is no argument to have. Above it, code wins, and the gap widens linearly with volume. The split option is interesting here because it usually sits under the crossover for the routing part (few branches, cheap runs) while moving the expensive, high-volume step to code — which is often the step that was generating most of the runs in the first place.
Criterion 5: what the migration actually looks like
The migration is rarely all-or-nothing, and planning it as a rewrite is the most common way to stall it. The common end state is a flow that handles routing and a service that handles the one step needing real logic. Concretely: the flow still owns the trigger, still branches on the simple attributes — which folder, which tag, which upload preset — and still delivers the asset to its outcome, whether that is a moderation queue or approval routing inside the flow. The one branch that grew fifteen sub-branches, or the one block that needed a loop, or the one decision you wanted a test for, becomes an endpoint the flow calls.
Whether your canvas can delegate a step to an external endpoint at all is a question to settle in the block reference before you design around it; do not assume it. If it cannot, the split becomes two automations that share an event source — the flow handles what it can, and the service subscribes to the same notifications for the case the flow skips — which is a less tidy shape but a workable one.
Standing of each option: staying on the canvas means the growth continues and the fifteen branches become twenty. A full rewrite means re-implementing the twelve routing branches in code where they gain nothing and lose the non-developer editability that was the point. The split moves only what needed to move.
Criterion 6: the cost of moving at the wrong time
The timing risk is asymmetric, and naming the asymmetry usually settles the argument. Moving early costs a developer: some days of build, and the loss of a canvas that operations could edit alone. Moving late costs an incident nobody could review afterwards — a bad edit on a fifteen-branch flow, no diff to read, no test that would have caught it, and a post-mortem that ends in ‘we are not sure which change did it’.
Which cost is worse depends entirely on what the flow touches, which is the reviewability threshold again from the other side. A flow that regenerates alt text can afford to move late; a wrong week is a regenerate. A flow that deletes, that gates publication, or that writes into a system of record cannot, because the incident is the irreversible kind. The PowerFlows catalogue is a useful reading of where Cloudinary itself has judged the canvas safe enough to ship prebuilt: moderation, UGC deletion, multilingual alt text, CSV upload — each a short sequence with one decision. The moment your version of one of those has grown conditions of your own, you have left the envelope those were designed for.
One more thing the agent surface does not change: an automation built by an agent through the MediaFlows MCP server is still a canvas. It is faster to produce and no easier to review, so the threshold sits exactly where it sat before.
Which to pick when
Pick the canvas if the flow has around three branches or fewer, no step carries state from one iteration to the next, a wrong run is visible and cheap to reverse, monthly runs sit below the crossover you calculated, and the people who will change it next are not developers. The prebuilt PowerFlows and a modest EasyFlow are squarely here; so is anything you would happily let a new hire edit on their first week.
Pick code if any one of these is true: the logic loops with state across iterations, you have caught yourself wanting to write an assertion about it, a wrong run deletes or publishes something you cannot take back, or volume is above the crossover. One is enough. These do not average out against the conveniences of the canvas; each on its own means the convenience is being paid for in risk.
Pick the split — a flow that routes and a service that handles the one hard step — when most of the automation is routing and one part trips a signal above. This is the common end state and, more often than not, the right first move: it is a smaller change than a rewrite, it keeps the non-developer editability where it was harmless, and it puts a test suite around exactly the step that needed one. If you are building your first flow now rather than migrating one, the shape to aim for from the start is described in building a first media automation flow from blocks: keep it short enough that the question on this page does not come up for a while.
If you are unsure which of the three you are looking at, ask the reviewability question directly: what does the worst plausible edit to this flow cost, and is that more than the cost of needing a developer to make it? Answer that honestly and the rest of the criteria mostly confirm what you already know.
Sources
- MediaFlowscloudinary.com
- Admin APIcloudinary.com
- Cloudinary pricingcloudinary.com
- how credits are countedcloudinary.com
- PowerFlows cataloguecloudinary.com
See also
Keep editor labels flexible while public identifiers, overwrite rules, folders, and external keys stay predictable.
How no-code media delivery negotiates image formats, adjusts compression, preserves source assets, and keeps CDN cache variants compatible.
Generate alt text inside a MediaFlows automation, write it back to asset metadata, and keep decorative images out of the flow.
How to build a media automation flow that expires assets on a date you chose, restricts before it deletes, and shows up in the storage bill the day it runs.