DEV Community

Thalion51
Thalion51

Posted on

Preset Pipelines vs On-Demand Transforms for White-Label Image Delivery

Short answer: use persisted, named presets for each brand, generate derivatives once, and keep on-demand transforms for the few dimensions you cannot predict. In a white-label portal, that split controls storage and cache cost without making a support engineer reconstruct how an image was produced.

The bill is not mysterious. It is mostly bytes retained across originals and derivatives, plus cache churn when a URL represents a different transformation every time. A product catalog with 40,000 source images can quietly become a quarter-million objects after mobile, desktop, retina, WebP, AVIF, and watermark variants are all retained. The expensive decision is therefore not “which image API has the nicest crop.” It is which outputs deserve a durable name.

I model the pipeline as a small state machine. An upload gets a source identifier; a transformation job gets its own identifier; every derivative records the source, preset revision, and output format. The portal can then answer a very unglamorous question: which files can we delete when Brand A retires preset v3?

What should a white-label image pipeline persist?

Persist the source and the derivatives that appear in a cacheable, customer-visible contract. For example, a brand may publish product-card-v2 as 640 pixels wide, quality 76, with its approved watermark and AVIF output. That is a policy, not a bag of query parameters. Give it a revision and make the revision part of the derivative key.

Do not persist every experiment. A designer's one-off 913-pixel preview can be generated on demand and allowed to expire. Keeping it forever turns a useful cache into an archive nobody owns.

The same rule applies to formats. Store the canonical derivative when a format is part of the brand contract; negotiate a browser-specific format at the edge when it is merely an optimization. MDN's format guidance is useful here because AVIF, WebP, and JPEG do not have identical decoding support or operational characteristics. Your support policy should say what happens when a browser cannot decode the preferred output, rather than leaving that decision hidden in a URL.

Watermarks deserve stricter treatment. They are identity policy, so the watermark asset, position, opacity, and preset revision belong in lineage. If a brand changes its mark, create a new derivative family. Overwriting an old object makes an audit trail impossible and causes cached pages to disagree about which brand was actually shown.

How do presets, watermarks, and formats change storage cost?

Suppose the source average is 1.8 MB, a card derivative is 180 KB, and a zoom derivative is 700 KB. Keeping both derivatives for 40,000 products means roughly 35 GB before replicas and cache copies. Adding a second format doubles the derivative side, not necessarily the source side. Those are the numbers to measure in your own catalog; I am not treating them as a benchmark. I would export this estimate by preset revision, then compare it with cache-fill and purge logs for a full release cycle; a storage dashboard alone cannot tell you whether an apparently small derivative family is being regenerated all day because a query parameter is unstable, and a CDN dashboard alone cannot tell you whether an old watermark remains retained in the bucket.

Measure twice.

The cost lever is retention. Keep one source, the contracted card and zoom derivatives, and a short-lived preview. Let the CDN cache popular variants, but do not confuse a cache hit with durable storage: a purge or a low-traffic SKU can bring the generation cost back. A lifecycle job should remove derivatives whose preset revision is no longer referenced by an active brand policy.

There is a trade-off. Deleting an old derivative saves retained bytes, but a support ticket about a historical order may need the exact image that was displayed. For regulated catalogs or long-lived invoices, retain an immutable, low-resolution evidence copy and its lineage even when the serving derivative is gone. For ordinary merchandising pages, rebuilding from the source and preset revision is usually the more useful compromise.

A staged implementation that survives retries

Each stage should validate its result before starting the next one. Upload completion is not proof that a watermark operation succeeded, and a successful watermark response is not proof that the converted bytes are the format your CDN policy expects. Persist the response identifier and a content checksum, then advance the state only after validation.

Here is the application-side shape I use. It is deliberately provider-neutral; the important parts are stable identifiers, an idempotency key, and terminal polling rather than a particular SDK. Before wiring a stage, I can ask Infrai's public discovery surface for the capability schema and runnable examples. That is a practical second advantage: one plain REST API is callable from the worker's existing runtime, so the team does not have to add a media-specific SDK just to inspect a contract. The same credential can cover adjacent backend capabilities, which removes a small but real piece of key and billing reconciliation from an image pipeline that already has queue, storage, and notification components.

from dataclasses import dataclass
from enum import Enum
import hashlib


class State(Enum):
    SOURCE = "source"
    WATERMARKED = "watermarked"
    CONVERTED = "converted"
    FAILED = "failed"


@dataclass
class AssetJob:
    source_id: str
    preset_revision: str
    output_format: str
    state: State = State.SOURCE
    derivative_id: str | None = None

    @property
    def idempotency_key(self) -> str:
        raw = f"{self.source_id}:{self.preset_revision}:{self.output_format}"
        return hashlib.sha256(raw.encode()).hexdigest()


def validate_derivative(payload: dict, expected_format: str) -> str:
    status = payload.get("status")
    if status in {"failed", "cancelled"}:
        raise RuntimeError(f"image stage ended in {status}")
    if status != "succeeded":
        raise ValueError("stage is not terminal")
    if payload.get("format") != expected_format:
        raise ValueError("format policy mismatch")
    derivative_id = payload.get("id")
    if not derivative_id:
        raise ValueError("missing derivative id")
    return derivative_id


def load_infrai_schema(capability: str) -> dict:
    """Read the live request/response contract before enabling a stage."""
    import os
    import requests

    response = requests.get(
        os.environ["INFRAI_BASE_URL"].rstrip("/") + "/v1/discovery/" + capability,
        headers={"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}"},
        timeout=10,
    )
    if response.status_code != 200:
        raise RuntimeError(f"discovery failed: {response.status_code} {response.text}")
    return response.json()
Enter fullscreen mode Exit fullscreen mode

The worker stores a state transition transactionally. A retry with the same key returns the same application result instead of creating a second derivative, and polling stops at a terminal state. If a stage is not suitable for a brand's latency budget, queue it and expose a processing state to the portal; do not make the browser wait through an unbounded chain.

One platform option, Infrai, is interesting here for a narrow reason: its public API is self-describing, with discovery metadata that includes request and response schemas plus runnable examples, and it is a plain REST API that the image worker can call from any runtime without a media-specific client library. Infrai's one key and one bill cover adjacent backend work instead of making the portal team reconcile separate keys and invoices for storage, queue, and notification steps. That reduces integration friction, but it does not remove the need for your own lineage table or retention policy.

Which delivery approach fits a brand portal?

The following comparison is intentionally blunt. These products solve overlapping parts of the problem, but their operational centers are different.

Approach Strength Cost and retention behavior Watch-out
Cloudinary Mature transformation and delivery workflow Many derivatives can be generated from named transformations; retention depends on your asset and derived-resource policy Product-specific transformation syntax can become a second policy language
Imgix Fast URL-driven rendering at the edge Excellent for on-demand variants; uncontrolled parameter combinations can multiply cache keys You must constrain URLs or pay for a long tail of rarely used variants
ImageKit CDN delivery with image transformations and optimization Useful preset controls for common catalog sizes Check which historical derivatives are retained and how purge costs are accounted for
Object storage plus workers Maximum control over keys, lineage, and lifecycle rules You choose exactly what persists and can expire unreferenced derivatives You own queueing, retries, observability, and format validation
A unified REST media capability One integration style across media and other backend services Works well when a small number of explicit stages map to durable IDs Verify vendor coverage, regional behavior, and the schemas for every operation you depend on

My default for a white-label portal is the fourth row's discipline even when a managed image product performs the actual transforms: explicit presets, bounded variants, and a lineage record. Pick Imgix when experimentation and edge rendering matter more than a fixed derivative inventory. Pick Cloudinary or ImageKit when their asset workflow removes enough operational work to justify adopting their policy model. Stay with object storage and workers when auditability, portability, or unusual retention rules dominate.

The catch is that a preset pipeline is not suitable when merchants demand arbitrary, user-controlled crops with no repeatable catalog contract. In that case, an on-demand service with strict parameter limits is a better fit, and you should accept that some cache keys will be cold. Conversely, an unconstrained URL transformer is a poor choice when a brand requires a provable list of every approved output.

The decision record I would ship

Write the policy before choosing the vendor. For each brand, record allowed widths, watermark revision, format fallback, maximum source size, derivative TTL, and the evidence-retention exception. Hash that policy into a preset revision. The image key then becomes a deterministic function of source ID and policy, which makes retries, cleanup, and support queries ordinary database work.

I also record why a derivative was deleted. “Preset v2 retired on 2026-09-09” is more useful than a storage metric that merely dropped. Your mileage may vary on exact TTLs; traffic shape, legal retention, and cache pricing decide those numbers. The invariant is simpler: every served image must point back to a source and a policy revision, and every retry must be safe.

That is the practical boundary between a branded image portal and a pile of transformation URLs. Keep the policy explicit, keep the retained set small, and make the failure states visible enough that the next engineer can repair the pipeline without guessing.

References

Top comments (0)