Development Choices

Design branching conditions in no-code media flows

Author
Joseph TrasattiMember of technical staff
Published
Section
No-Code
Length
7 min read3 sources cited
A precise media conveyor dividing into several clearly bounded decision paths

Normalize every metadata field before branching, then define non-overlapping predicates so each asset can reach only one side-effecting path. Route everything unmatched through a final else branch and make that path observable. Test canonical, case-variant, whitespace, absent, and unknown values before putting the flow into use.

Prerequisites

A no-code flow normalizes input, evaluates rules, follows a known or else branch, and records the outcome
An explicit else branch turns taxonomy drift into a visible event.

Before changing the flow, write down the metadata field that controls routing, its accepted values, and the path assigned to each value. Treat that list as the routing contract. If the field is populated earlier in the workflow, settle its output contract while designing the metadata-enrichment step, not after the branches have already been built.

Also mark every path that has side effects: any path that changes state outside the condition itself. Duplicate reads may waste work, but duplicate side effects can leave the asset processed in two conflicting ways. If you have not assembled the trigger and basic block sequence yet, complete the first media automation flow before adding conditional routing.

Cloudinary’s guide to building a flow, checked 2026-08-18, is the reference for assembling the flow. The steps below concern the routing contract inside that flow.

Steps

  1. Turn the routing requirement into a decision table.

    Give every accepted normalized value exactly one destination. Do this before placing condition blocks, because a table makes overlaps and omissions visible without requiring anyone to interpret the canvas.

    A minimal table might look like this:

    Normalized value Destination Side effects allowed?
    ready Ready path Only those assigned to this path
    hold Hold path Only those assigned to this path
    Anything else Final else path Observable handling only

    The names are placeholders; use the values defined for your own metadata field. The important constraint is that one normalized value maps to one path. If a value appears in two rows, the design is already ambiguous. If a value appears in no row and there is no else row, it can disappear from the intended workflow without a visible result.

    Do not start with broad conditions such as “not hold” and add narrower conditions later. A newly introduced value could satisfy the broad test even though nobody deliberately assigned it to that path. Exact accepted values plus a final else branch produce a routing contract that is easier to inspect and test.

  2. Normalize the routing value before evaluating any condition.

    Branch conditions should use normalized metadata values. Case, surrounding whitespace, and absent fields otherwise create hidden branches: values that look equivalent to a person but produce different condition results.

    Choose one canonical form for the field. For a text value, that means deciding how case and surrounding whitespace are handled. Give an absent field an explicit internal sentinel rather than allowing it to pass through as an unexamined blank. The sentinel must not be one of the accepted business values; its purpose is to reach the fallback path predictably.

    For example, READY, ready, and ready should be reduced to the same canonical value if the routing contract considers them equivalent. An absent field should become a distinct fallback value, not accidentally resemble an accepted empty value. This normalization is part of the flow’s logic, not a cleanup to add after routing fails.

    Use Cloudinary’s structured metadata documentation, checked 2026-08-18, to confirm the field being read, then consult the MediaFlows block reference, checked 2026-08-18, for the blocks available to produce and test the canonical value. Do not assume a block performs trimming, case normalization, or absent-value handling unless its documented behavior says so.

    Preserve only the information needed to diagnose a fallback. If observability would expose unnecessary metadata, apply the same field-level restraint used for data minimization across no-code blocks.

  3. Define mutually exclusive branch conditions.

    Each accepted normalized value should satisfy one condition and fail every other condition. Branch conditions must be mutually exclusive because the same asset may otherwise enter more than one side-effecting path.

    Prefer direct equality against the canonical values in the decision table. If a condition must accept several values, list that set explicitly and verify that none of its members appears in another condition. Avoid overlapping tests such as one branch matching a prefix while another matches a complete value inside that prefix. The overlap may be easy to miss on a visual canvas even when each condition looks reasonable in isolation.

    Do not use block order as the safety mechanism. A design that is correct only if one branch runs first is harder to review and easier to break when somebody rearranges the flow. Make the predicates non-overlapping themselves. Then the routing decision remains clear from the conditions, independent of their visual position.

    This is also where policy-specific work belongs. If the branches enforce file handling rules, define the accepted canonical values in the media format policy and keep that policy aligned with the decision table. A branch should implement a named policy outcome, not infer one from loosely formatted input.

  4. Connect every unmatched value to a final else branch.

    Add the else branch after all recognized cases. It must catch absent sentinels, malformed values, and values introduced later but not yet added to the routing table. A final else branch makes those values observable instead of silently dropping them.

    Connect the branch to an outcome that the team can inspect using the facilities already chosen for the flow. “Observable” means an operator can tell that an asset reached the fallback and can identify the routing value that caused it, subject to the flow’s data-minimization rules. An unconnected else line or a path that ends without an inspectable outcome still behaves like a silent drop.

    Do not route the else branch into a normal side-effecting path merely to keep the flow moving. An unknown value has not been assigned a valid outcome. Treating it as a recognized case hides the contract violation and makes a later schema change look successful when it was never reviewed.

  5. Keep side effects behind the completed routing decision.

    Place each path’s side effects only after normalization and the mutually exclusive conditions. Do not copy the same side effect into several branches unless repeated execution is deliberately part of the written routing contract.

    Review the canvas path by path. Starting from one normalized value, trace every connector it can follow and count the side-effecting paths it reaches. The correct count is one for every accepted value. For an unknown or absent value, the only destination should be the observable else path.

    This review catches a structural error that condition text alone does not: two exclusive conditions can still feed into duplicated downstream actions. The decision table describes the intended destination, while the canvas confirms that the actual connections implement it.

  6. Test the routing contract with boundary inputs.

    Run at least one test for every accepted canonical value, then test the input variations that create hidden branches. Record the expected destination before running each case.

    Test input Expected result
    Each accepted canonical value Its one assigned path
    Same value with different case Same path after normalization
    Same value with surrounding whitespace Same path after normalization
    Absent field Final else path
    Unrecognized value Final else path
    Newly proposed value, before adding a branch Final else path

    For every case, verify both halves of the contract: the asset reached the expected destination, and it did not enter another side-effecting path. Checking only the visible successful path misses duplicate execution.

    When a new metadata value is introduced, update the decision table first, add one mutually exclusive condition, and repeat the full table. Do not weaken an existing condition to absorb the value unless both values genuinely require the same outcome and the accepted set remains explicit.

Expected result

The finished flow normalizes its routing metadata before testing it, sends each accepted value through exactly one side-effecting path, and sends absent, malformed, or newly introduced values to an observable final else path. The decision table, branch predicates, connections, and boundary tests describe the same routing contract.

Sources

  1. guide to building a flowcloudinary.com
  2. structured metadata documentationcloudinary.com
  3. MediaFlows block referencecloudinary.com

See also