{"id":40356,"date":"2026-09-01T07:00:00","date_gmt":"2026-09-01T14:00:00","guid":{"rendered":"https:\/\/cloudinary.com\/blog\/?p=40356"},"modified":"2026-09-01T10:49:27","modified_gmt":"2026-09-01T17:49:27","slug":"your-model-returns-file-production-needs-asset","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/your-model-returns-file-production-needs-asset","title":{"rendered":"Your Model Returns a File. Production Needs an Asset."},"content":{"rendered":"\n<p>Your agent calls an AI image or video model (OpenAI, Google, Runway, fal) and, a few seconds later, gets back a URL or a blob of base64. Feels like the job is done. It isn&#8217;t. That raw output will probably expire, it&#8217;s the wrong size and format for wherever it&#8217;s headed, it carries no record of what made it, and nobody has checked it against your brand. And because it&#8217;s an agent, there&#8217;s no human standing by to fix any of that.<\/p>\n\n\n\n<p>The disappearing URL gets all the attention, but it&#8217;s only the first of several steps between &#8220;the model responded&#8221; and &#8220;I can ship this.&#8221; Here&#8217;s the whole path.<\/p>\n\n\n\n<p>What this covers: what happens when generated media expires across the major APIs, what &#8220;production-ready&#8221; actually requires (persist, transform, deliver, brand, find), and how to collapse that pipeline into one step.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 0: The Output is Built to Disappear<\/h2>\n\n\n\n<p>Generated media is ephemeral by default, and the details vary more than you&#8217;d expect:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>OpenAI.<\/strong> Image models like <code>gpt-image-2<\/code> return base64 bytes, no hosted URL at all, so you own storage from the first response. Sora video files last ~48 hours (download URLs ~1 hour), and the Sora video <strong>API is being sunset in September 2026<\/strong>.<\/li>\n\n\n\n<li><strong>Google.<\/strong> The current image models, <strong>Nano Banana 2 (Gemini 3.1 Flash Image) <\/strong>and <strong>Nano Banana Pro (Gemini 3 Pro Image)<\/strong>, return bytes inline through the Gemini API. For video, <strong>Veo 3.1<\/strong> output is kept <strong>two days<\/strong> behind the Files API, then deleted.<\/li>\n\n\n\n<li><strong>Runway.<\/strong> Gen-4 image and video output URLs expire in roughly <strong>24-48 hours<\/strong>; the docs tell you plainly to download and self-host.<\/li>\n<\/ul>\n\n\n\n<p>This isn&#8217;t a bug. These are inference platforms, not asset hosts, and serving files forever is expensive. The trap is that &#8220;save it before it vanishes&#8221; quietly became <em>your<\/em> job, and most teams only find out when a link 404s in production.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Persistence Alone Isn&#8217;t the Finish Line<\/h2>\n\n\n\n<p>The landscape is shifting, to be fair. <strong>fal.ai now offers fal Assets<\/strong>, where generations persist instead of expiring, and platforms like Leonardo keep outputs indefinitely. Even routing layers like <strong>OpenRouter&#8217;s Unified Image API<\/strong> give you one endpoint across dozens of models, though as a router it stores nothing, so persistence is still yours to solve.<\/p>\n\n\n\n<p>But solving expiry only solves step zero. A file that lives forever in one vendor&#8217;s library is still unoptimised, unbranded, scattered across whichever providers you happen to use, and only as findable as that vendor&#8217;s UI. The hard part was never just keeping the bytes.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Why Autonomous Agents Make Media Persistence Harder<\/h2>\n\n\n\n<p>When a person generates an image in a web UI, they&#8217;re right there to download it, crop it, eyeball the brand, and drop it where it belongs. Agentic workflows delete that entire safety net.<\/p>\n\n\n\n<p>An agent runs in the background. It calls a model, gets a result, and moves on: the output lands in a state object or a database row, and nobody looks until much later. Good agent-state design even says to store large artifacts as files and keep only the path in state. Sound advice, but it assumes the file is somewhere permanent and usable. A raw model URL is neither. So every step a human would have done by hand now has to happen automatically, at generation time. That&#8217;s the actual job.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What &#8216;Production-Ready&#8217; Actually Means<\/h2>\n\n\n\n<p>Strip it back to what has to be true before generated media can ship:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Persisted. <\/strong>Captured the instant it&#8217;s created, so nothing depends on an expiring URL.<\/li>\n\n\n\n<li><strong>Optimized and transformed. <\/strong>The right format and size for each destination. A 4 MB PNG becomes a 40 KB WebP thumbnail, a social crop, an AVIF for modern browsers. Video is harder: transcoding to MP4\/WebM, an adaptive HLS\/DASH stream, a poster frame, often a trimmed cut, all from one master.<\/li>\n\n\n\n<li><strong>Delivered. <\/strong>Served fast from a CDN, video streamed adaptively rather than shipped whole from one region.<\/li>\n\n\n\n<li><strong>On-brand. <\/strong>Checked against brand rules before a customer sees it. An agent generating customer-facing media with no brand guardrail is a real risk, not a hypothetical.<\/li>\n\n\n\n<li><strong>Findable. <\/strong>Stored with its metadata: prompt, model, use-case, tags, and for video things like duration and captions. An agent that can&#8217;t search its own output regenerates the same thing twice.<\/li>\n<\/ul>\n\n\n\n<p>Miss any one of these and you don&#8217;t have an asset; you have a raw output and a to-do list.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">This is Really an Asset Pipeline<\/h3>\n\n\n\n<p>Every one of those requirements already exists in traditional media workflows. AI generation hasn&#8217;t removed the pipeline, it has simply automated the first step. Agents make that more obvious because there&#8217;s no human left to bridge the gap manually.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Building the Media Pipeline Yourself<\/h2>\n\n\n\n<p>The pattern everyone reaches for looks simple:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>generate \u2192 download the bytes \u2192 push to your object store \u2192 serve from there<\/p>\n<\/blockquote>\n\n\n\n<p>The store is usually S3, Cloudflare R2, or Supabase, and the mechanics are well-trodden. But persisting the bytes is the easy ~60%. What&#8217;s left on your plate:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Glue code on every generation path<\/strong>, with retries for when the URL expires mid-download (worse for large video files).<\/li>\n\n\n\n<li><strong>A transformation service<\/strong> (Lambda + sharp, imgix) and, for video, a transcoding pipeline (FFmpeg or managed) for streamable renditions and poster frames.<\/li>\n\n\n\n<li><strong>A CDN<\/strong> in front, with adaptive streaming for video.<\/li>\n\n\n\n<li><strong>A brand check<\/strong>, which most pipelines just skip.<\/li>\n\n\n\n<li><strong>A metadata store<\/strong> you build and maintain so assets stay findable.<\/li>\n<\/ul>\n\n\n\n<p>You can absolutely assemble this, and if storage cost dominates and your transform needs are light, R2-plus-a-Worker is a sensible call. Just be honest that you&#8217;re now operating a small media pipeline, not a bucket.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">2 Pipelines, 1 Call<\/h2>\n\n\n\n<p>The model step is identical either way. What differs is everything after it.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/v1786491323\/Your_Model_Returns_a_File._Production_Needs_an_Asset.-1.webp\" alt=\"Two pipelines: the DIY chain of services versus a single managed step\"\/><\/figure>\n<\/div>\n\n\n<p>The generation call below is deliberately abstracted: whether <code>generateMedia()<\/code> wraps OpenAI, Google, Runway, fal, or an OpenRouter route, you&#8217;re left holding the same thing: an ephemeral URL you now have to productionise.<\/p>\n\n\n\n<p><strong>The DIY way:<\/strong> Download, race the expiry, persist, then start the rest of the pipeline.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> { S3Client, PutObjectCommand } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@aws-sdk\/client-s3\"<\/span>;\n<span class=\"hljs-keyword\">const<\/span> s3 = <span class=\"hljs-keyword\">new<\/span> S3Client({ <span class=\"hljs-attr\">region<\/span>: process.env.AWS_REGION });\n\n<span class=\"hljs-keyword\">const<\/span> modelOutputUrl = <span class=\"hljs-keyword\">await<\/span> generateMedia(prompt); <span class=\"hljs-comment\">\/\/ any provider; ephemeral<\/span>\n\n<span class=\"hljs-keyword\">const<\/span> res = <span class=\"hljs-keyword\">await<\/span> fetch(modelOutputUrl); <span class=\"hljs-comment\">\/\/ race the clock<\/span>\n<span class=\"hljs-keyword\">if<\/span> (!res.ok) <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Error<\/span>(Model URL expired: ${res.status});\n<span class=\"hljs-keyword\">const<\/span> bytes = Buffer.from(<span class=\"hljs-keyword\">await<\/span> res.arrayBuffer());\n\n<span class=\"hljs-keyword\">await<\/span> s3.send(<span class=\"hljs-keyword\">new<\/span> PutObjectCommand({\n<span class=\"hljs-attr\">Bucket<\/span>: process.env.S3_BUCKET,\n<span class=\"hljs-attr\">Key<\/span>: generations\/${<span class=\"hljs-built_in\">Date<\/span>.now()}.png,\n<span class=\"hljs-attr\">Body<\/span>: bytes,\n<span class=\"hljs-attr\">ContentType<\/span>: <span class=\"hljs-string\">\"image\/png\"<\/span>,\n}));\n\n<span class=\"hljs-comment\">\/\/ Still TODO, separately: transform\/transcode, CDN, brand check, metadata store\u2026<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><strong>The pluggable way:<\/strong> Hand the same URL to a media pipeline and get a production asset back in one call. (This example uses Cloudinary, but the shape is what matters.)<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> { v2 <span class=\"hljs-keyword\">as<\/span> cloudinary } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"cloudinary\"<\/span>; <span class=\"hljs-comment\">\/\/ configured from CLOUDINARY_URL<\/span>\n\n<span class=\"hljs-keyword\">const<\/span> asset = <span class=\"hljs-keyword\">await<\/span> cloudinary.uploader.upload(<span class=\"hljs-keyword\">await<\/span> generateMedia(prompt), {\n<span class=\"hljs-attr\">folder<\/span>: <span class=\"hljs-string\">\"agent-generations\"<\/span>,\n<span class=\"hljs-attr\">context<\/span>: { prompt, <span class=\"hljs-attr\">model<\/span>: modelName }, <span class=\"hljs-comment\">\/\/ searchable metadata<\/span>\n<span class=\"hljs-attr\">eager<\/span>: &#91;{ <span class=\"hljs-attr\">width<\/span>: <span class=\"hljs-number\">400<\/span>, <span class=\"hljs-attr\">height<\/span>: <span class=\"hljs-number\">400<\/span>, <span class=\"hljs-attr\">crop<\/span>: <span class=\"hljs-string\">\"fill\"<\/span>,\n<span class=\"hljs-attr\">fetch_format<\/span>: <span class=\"hljs-string\">\"auto\"<\/span>, <span class=\"hljs-attr\">quality<\/span>: <span class=\"hljs-string\">\"auto\"<\/span> }], <span class=\"hljs-comment\">\/\/ optimised derivative<\/span>\n});\n\nasset.secure_url; <span class=\"hljs-comment\">\/\/ permanent original, CDN-delivered<\/span>\nasset.eager&#91;<span class=\"hljs-number\">0<\/span>].secure_url; <span class=\"hljs-comment\">\/\/ optimised WebP thumbnail<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>It fetches the bytes (no expiry race in your code), stores a permanent original, derives renditions on demand, and tags it with its metadata. Pass <code>resource_type: \"video\"<\/code> and the eager transforms become an adaptive stream and a poster frame instead of image crops. Same call for an image from one provider or a clip from another, and the agent ends up holding one stable, branded, findable URL, no per-model recipe required.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Or Generate Straight Into Your Asset Platform<\/h2>\n\n\n\n<p>If the generator and the asset platform are the same system, there&#8217;s no ephemeral URL to rescue in the first place. That&#8217;s the idea behind Cloudinary&#8217;s new <a href=\"https:\/\/cloudinary.com\/blog\/cloudinary-image-generation-api-python\">Image Generation API<\/a>: a single <code>text_to_image<\/code> endpoint across best-in-class model families (FLUX.2, Nano Banana, GPT Image, Recraft, Ideogram), much like the routing layer from earlier, except the output lands as a managed asset rather than a disappearing link.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">curl -X POST https:<span class=\"hljs-comment\">\/\/api.cloudinary.com\/v2\/generate\/\/text_to_image \\<\/span>\n-u <span class=\"hljs-string\">\":\"<\/span> \\\n-H <span class=\"hljs-string\">\"Content-Type: application\/json\"<\/span> \\\n-d <span class=\"hljs-string\">'{\n\"prompt\": \"a golden retriever wearing a tiny astronaut helmet\",\n\"model\": { \"family\": \"flux\", \"tier\": \"premium\" },\n\"target\": { \"target_type\": \"managed_asset\" }\n}'<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The response is a permanent <code>secure_url <\/code>plus the <code>asset_id<\/code> and <code>public_id<\/code> you use everywhere else in Cloudinary. The image is born persisted, optimizable, and ready to deliver; generation and production collapse into one step. (Omit model for the Nano Banana default; target defaults to a short-lived temporary asset if you&#8217;d rather not persist.)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The Takeaway<\/h2>\n\n\n\n<p>The honest version: if all you need is the cheapest bucket, R2 wins on raw storage cost, and Supabase now bundles basic transforms and a CDN. Reach for a full media platform when the whole job matters (persist, transform, deliver, keep on-brand, organise) and you&#8217;d rather make one call than orchestrate five.<\/p>\n\n\n\n<p>But the broader lesson outlives any product choice. <strong>In an agentic system, a generated file is an intermediate value, not a deliverable. <\/strong>The model is a component, not the finish line. Treat the path from raw output to production asset as a real pipeline (whether you build it from buckets, workers, transcoders and a metadata table, or hand it to something that does all five) and your agents stop storing links to nothing.<\/p>\n\n\n\n<p>Ready to level up your media workflow? <a href=\"https:\/\/cloudinary.com\/users\/register_free\">Start using Cloudinary<\/a> for free and build better visual experiences today.<\/p>\n\n\n\n<style>\n.faqs {\n    padding: 30px 60px;\n    margin-top: 40px;\n    background: var(--color-background-offset);\n    border-radius: 20px;\n}\n\n#frequently_asked_questions {\n    margin-bottom: 20px;\n}\n\n.question {\n    margin-bottom: 12px;\n    border-bottom: 1px solid rgba(0, 0, 0, 0.12);\n}\n\n.question summary {\n    position: relative;\n    padding: 18px 40px 18px 0;\n    cursor: pointer;\n    font-weight: 700;\n    list-style: none;\n}\n\n.question summary::-webkit-details-marker {\n    display: none;\n}\n\n.question summary::after {\n    content: \"+\";\n    position: absolute;\n    top: 50%;\n    right: 0;\n    transform: translateY(-50%);\n    font-size: 24px;\n    font-weight: 400;\n    line-height: 1;\n}\n\n.question[open] summary::after {\n    content: \"\u2212\";\n}\n\n.answer {\n    padding: 0 40px 20px 0;\n}\n\n.answer ul {\n    margin: 12px 0;\n    padding-left: 20px;\n}\n<\/style>\n\n<div class=\"faqs\">\n\n<h2 id=\"frequently_asked_questions\">Frequently Asked Questions<\/h2>\n\n<details class=\"question\">\n    <summary>What is an AI media pipeline?<\/summary>\n    <div class=\"answer\">\n        An AI media pipeline is the workflow that transforms raw AI-generated content into production-ready assets. In addition to generation, it typically includes persistent storage, image and video optimization, format conversion, CDN delivery, metadata management, brand governance, and searchable asset organization. Rather than treating generation as the final step, an AI media pipeline prepares assets for real-world applications across websites, apps, and marketing channels.\n    <\/div>\n<\/details>\n\n<details class=\"question\">\n    <summary>Can AI-generated videos be optimized automatically?<\/summary>\n    <div class=\"answer\">\n        Yes. Production-ready video workflows include transcoding to streaming formats, adaptive bitrate streaming such as HLS or DASH, poster image generation, responsive delivery, and AI-generated captions or transcripts. These <a href=\"https:\/\/cloudinary.com\/documentation\/video_manipulation_and_delivery\">optimizations<\/a> help improve playback quality while reducing bandwidth requirements.\n    <\/div>\n<\/details>\n\n<details class=\"question\">\n    <summary>Why should AI-generated assets include metadata?<\/summary>\n    <div class=\"answer\">\n        <a href=\"https:\/\/cloudinary.com\/documentation\/digital_asset_management_overview#full_metadata_control\">Metadata<\/a> makes AI-generated content searchable and reusable. Storing information such as prompts, model names, tags, generation dates, campaigns, and usage rights allows teams and AI agents to locate existing assets instead of generating duplicate content.\n    <\/div>\n<\/details>\n\n<details class=\"question\">\n    <summary>Can Cloudinary work with multiple AI image generation models?<\/summary>\n    <div class=\"answer\">\n        Yes. <a href=\"https:\/\/cloudinary.com\/documentation\/image_generation_addon\">Cloudinary&#8217;s Image Generation API<\/a> provides a unified interface for multiple leading image generation model families, allowing developers to generate and manage AI images within the same media platform. Generated assets can be stored as managed assets, optimized, transformed, and delivered using the same Cloudinary APIs.\n    <\/div>\n<\/details>\n\n<details class=\"question\">\n    <summary>How does Cloudinary help AI agents manage generated media?<\/summary>\n    <div class=\"answer\">\n        Cloudinary enables AI agents to automatically persist generated assets, optimize images and videos, organize them with searchable metadata, apply transformations, and deliver them through a global CDN. This allows agents to produce production-ready media without requiring separate storage, optimization, and delivery workflows.\n    <\/div>\n<\/details>\n\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Your agent calls an AI image or video model (OpenAI, Google, Runway, fal) and, a few seconds later, gets back a URL or a blob of base64. Feels like the job is done. It isn&#8217;t. That raw output will probably expire, it&#8217;s the wrong size and format for wherever it&#8217;s headed, it carries no record [&hellip;]<\/p>\n","protected":false},"author":87,"featured_media":40408,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[1],"tags":[424,409,370],"class_list":["post-40356","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-agentic","tag-generative-ai","tag-image"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v28.3 (Yoast SEO v28.3) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Your Model Returns a File. Production Needs an Asset.<\/title>\n<meta name=\"description\" content=\"Your agent calls an AI image or video model (OpenAI, Google, Runway, fal) and, a few seconds later, gets back a URL or a blob of base64. Feels like the\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/dev.to\/cloudinary\/your-model-returns-a-file-production-needs-an-asset-17ac\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Your Model Returns a File. Production Needs an Asset.\" \/>\n<meta property=\"og:description\" content=\"Your agent calls an AI image or video model (OpenAI, Google, Runway, fal) and, a few seconds later, gets back a URL or a blob of base64. Feels like the\" \/>\n<meta property=\"og:url\" content=\"https:\/\/dev.to\/cloudinary\/your-model-returns-a-file-production-needs-an-asset-17ac\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-09-01T14:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-09-01T17:49:27+00:00\" \/>\n<meta name=\"author\" content=\"melindapham\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1788284946\/Web_Assets\/blog\/Blog_Your_model_returns_a_file._Production_needs_an_asset\/Blog_Your_model_returns_a_file._Production_needs_an_asset.jpg?_i=AA\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/dev.to\\\/cloudinary\\\/your-model-returns-a-file-production-needs-an-asset-17ac#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/cloudinary.com\\\/blog\\\/your-model-returns-file-production-needs-asset\"},\"author\":{\"name\":\"melindapham\",\"@id\":\"https:\\\/\\\/cloudinary.com\\\/blog\\\/#\\\/schema\\\/person\\\/0d5ad601e4c3b5be89245dfb14be42d9\"},\"headline\":\"Your Model Returns a File. Production Needs an Asset.\",\"datePublished\":\"2026-09-01T14:00:00+00:00\",\"dateModified\":\"2026-09-01T17:49:27+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/cloudinary.com\\\/blog\\\/your-model-returns-file-production-needs-asset\"},\"wordCount\":1638,\"publisher\":{\"@id\":\"https:\\\/\\\/cloudinary.com\\\/blog\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/dev.to\\\/cloudinary\\\/your-model-returns-a-file-production-needs-an-asset-17ac#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/res.cloudinary.com\\\/cloudinary-marketing\\\/images\\\/f_auto,q_auto\\\/v1788284946\\\/Web_Assets\\\/blog\\\/Blog_Your_model_returns_a_file._Production_needs_an_asset\\\/Blog_Your_model_returns_a_file._Production_needs_an_asset.jpg?_i=AA\",\"keywords\":[\"Agentic\",\"Generative AI\",\"Image\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2026\",\"copyrightHolder\":{\"@id\":\"https:\\\/\\\/cloudinary.com\\\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/cloudinary.com\\\/blog\\\/your-model-returns-file-production-needs-asset\",\"url\":\"https:\\\/\\\/dev.to\\\/cloudinary\\\/your-model-returns-a-file-production-needs-an-asset-17ac\",\"name\":\"Your Model Returns a File. Production Needs an Asset.\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/cloudinary.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/dev.to\\\/cloudinary\\\/your-model-returns-a-file-production-needs-an-asset-17ac#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/dev.to\\\/cloudinary\\\/your-model-returns-a-file-production-needs-an-asset-17ac#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/res.cloudinary.com\\\/cloudinary-marketing\\\/images\\\/f_auto,q_auto\\\/v1788284946\\\/Web_Assets\\\/blog\\\/Blog_Your_model_returns_a_file._Production_needs_an_asset\\\/Blog_Your_model_returns_a_file._Production_needs_an_asset.jpg?_i=AA\",\"datePublished\":\"2026-09-01T14:00:00+00:00\",\"dateModified\":\"2026-09-01T17:49:27+00:00\",\"description\":\"Your agent calls an AI image or video model (OpenAI, Google, Runway, fal) and, a few seconds later, gets back a URL or a blob of base64. Feels like the\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/dev.to\\\/cloudinary\\\/your-model-returns-a-file-production-needs-an-asset-17ac#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/dev.to\\\/cloudinary\\\/your-model-returns-a-file-production-needs-an-asset-17ac\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/dev.to\\\/cloudinary\\\/your-model-returns-a-file-production-needs-an-asset-17ac#primaryimage\",\"url\":\"https:\\\/\\\/res.cloudinary.com\\\/cloudinary-marketing\\\/images\\\/f_auto,q_auto\\\/v1788284946\\\/Web_Assets\\\/blog\\\/Blog_Your_model_returns_a_file._Production_needs_an_asset\\\/Blog_Your_model_returns_a_file._Production_needs_an_asset.jpg?_i=AA\",\"contentUrl\":\"https:\\\/\\\/res.cloudinary.com\\\/cloudinary-marketing\\\/images\\\/f_auto,q_auto\\\/v1788284946\\\/Web_Assets\\\/blog\\\/Blog_Your_model_returns_a_file._Production_needs_an_asset\\\/Blog_Your_model_returns_a_file._Production_needs_an_asset.jpg?_i=AA\",\"width\":4000,\"height\":2200},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/dev.to\\\/cloudinary\\\/your-model-returns-a-file-production-needs-an-asset-17ac#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/cloudinary.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Your Model Returns a File. Production Needs an Asset.\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/cloudinary.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/cloudinary.com\\\/blog\\\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/cloudinary.com\\\/blog\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/cloudinary.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/cloudinary.com\\\/blog\\\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\\\/\\\/cloudinary.com\\\/blog\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/cloudinary.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/res.cloudinary.com\\\/cloudinary-marketing\\\/images\\\/f_auto,q_auto\\\/v1649718331\\\/Web_Assets\\\/blog\\\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\\\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\\\/\\\/res.cloudinary.com\\\/cloudinary-marketing\\\/images\\\/f_auto,q_auto\\\/v1649718331\\\/Web_Assets\\\/blog\\\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\\\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\\\/\\\/cloudinary.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/cloudinary.com\\\/blog\\\/#\\\/schema\\\/person\\\/0d5ad601e4c3b5be89245dfb14be42d9\",\"name\":\"melindapham\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g\",\"caption\":\"melindapham\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Your Model Returns a File. Production Needs an Asset.","description":"Your agent calls an AI image or video model (OpenAI, Google, Runway, fal) and, a few seconds later, gets back a URL or a blob of base64. Feels like the","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/dev.to\/cloudinary\/your-model-returns-a-file-production-needs-an-asset-17ac","og_locale":"en_US","og_type":"article","og_title":"Your Model Returns a File. Production Needs an Asset.","og_description":"Your agent calls an AI image or video model (OpenAI, Google, Runway, fal) and, a few seconds later, gets back a URL or a blob of base64. Feels like the","og_url":"https:\/\/dev.to\/cloudinary\/your-model-returns-a-file-production-needs-an-asset-17ac","og_site_name":"Cloudinary Blog","article_published_time":"2026-09-01T14:00:00+00:00","article_modified_time":"2026-09-01T17:49:27+00:00","author":"melindapham","twitter_card":"summary_large_image","twitter_image":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1788284946\/Web_Assets\/blog\/Blog_Your_model_returns_a_file._Production_needs_an_asset\/Blog_Your_model_returns_a_file._Production_needs_an_asset.jpg?_i=AA","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/dev.to\/cloudinary\/your-model-returns-a-file-production-needs-an-asset-17ac#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/your-model-returns-file-production-needs-asset"},"author":{"name":"melindapham","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9"},"headline":"Your Model Returns a File. Production Needs an Asset.","datePublished":"2026-09-01T14:00:00+00:00","dateModified":"2026-09-01T17:49:27+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/your-model-returns-file-production-needs-asset"},"wordCount":1638,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/dev.to\/cloudinary\/your-model-returns-a-file-production-needs-an-asset-17ac#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1788284946\/Web_Assets\/blog\/Blog_Your_model_returns_a_file._Production_needs_an_asset\/Blog_Your_model_returns_a_file._Production_needs_an_asset.jpg?_i=AA","keywords":["Agentic","Generative AI","Image"],"inLanguage":"en-US","copyrightYear":"2026","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/your-model-returns-file-production-needs-asset","url":"https:\/\/dev.to\/cloudinary\/your-model-returns-a-file-production-needs-an-asset-17ac","name":"Your Model Returns a File. Production Needs an Asset.","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/dev.to\/cloudinary\/your-model-returns-a-file-production-needs-an-asset-17ac#primaryimage"},"image":{"@id":"https:\/\/dev.to\/cloudinary\/your-model-returns-a-file-production-needs-an-asset-17ac#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1788284946\/Web_Assets\/blog\/Blog_Your_model_returns_a_file._Production_needs_an_asset\/Blog_Your_model_returns_a_file._Production_needs_an_asset.jpg?_i=AA","datePublished":"2026-09-01T14:00:00+00:00","dateModified":"2026-09-01T17:49:27+00:00","description":"Your agent calls an AI image or video model (OpenAI, Google, Runway, fal) and, a few seconds later, gets back a URL or a blob of base64. Feels like the","breadcrumb":{"@id":"https:\/\/dev.to\/cloudinary\/your-model-returns-a-file-production-needs-an-asset-17ac#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/dev.to\/cloudinary\/your-model-returns-a-file-production-needs-an-asset-17ac"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/dev.to\/cloudinary\/your-model-returns-a-file-production-needs-an-asset-17ac#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1788284946\/Web_Assets\/blog\/Blog_Your_model_returns_a_file._Production_needs_an_asset\/Blog_Your_model_returns_a_file._Production_needs_an_asset.jpg?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1788284946\/Web_Assets\/blog\/Blog_Your_model_returns_a_file._Production_needs_an_asset\/Blog_Your_model_returns_a_file._Production_needs_an_asset.jpg?_i=AA","width":4000,"height":2200},{"@type":"BreadcrumbList","@id":"https:\/\/dev.to\/cloudinary\/your-model-returns-a-file-production-needs-an-asset-17ac#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Your Model Returns a File. Production Needs an Asset."}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9","name":"melindapham","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g","caption":"melindapham"}}]}},"parsely":{"version":"1.1.0","canonical_url":"https:\/\/cloudinary.com\/blog\/your-model-returns-file-production-needs-asset","smart_links":{"inbound":0,"outbound":0},"traffic_boost_suggestions_count":0,"meta":{"@context":"https:\/\/schema.org","@type":"NewsArticle","headline":"Your Model Returns a File. Production Needs an Asset.","url":"https:\/\/cloudinary.com\/blog\/your-model-returns-file-production-needs-asset","mainEntityOfPage":{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/your-model-returns-file-production-needs-asset"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1788284946\/Web_Assets\/blog\/Blog_Your_model_returns_a_file._Production_needs_an_asset\/Blog_Your_model_returns_a_file._Production_needs_an_asset.jpg?_i=AA&w=150&h=150&crop=1","image":{"@type":"ImageObject","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1788284946\/Web_Assets\/blog\/Blog_Your_model_returns_a_file._Production_needs_an_asset\/Blog_Your_model_returns_a_file._Production_needs_an_asset.jpg?_i=AA"},"articleSection":"Uncategorized","author":[{"@type":"Person","name":"melindapham"}],"creator":["melindapham"],"publisher":{"@type":"Organization","name":"Cloudinary Blog","logo":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA"},"keywords":["agentic","generative ai","image"],"dateCreated":"2026-09-01T14:00:00Z","datePublished":"2026-09-01T14:00:00Z","dateModified":"2026-09-01T17:49:27Z"},"rendered":"<meta name=\"parsely-title\" content=\"Your Model Returns a File. Production Needs an Asset.\" \/>\n<meta name=\"parsely-link\" content=\"https:\/\/cloudinary.com\/blog\/your-model-returns-file-production-needs-asset\" \/>\n<meta name=\"parsely-type\" content=\"post\" \/>\n<meta name=\"parsely-image-url\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1788284946\/Web_Assets\/blog\/Blog_Your_model_returns_a_file._Production_needs_an_asset\/Blog_Your_model_returns_a_file._Production_needs_an_asset.jpg?_i=AA&w=150&amp;h=150&amp;crop=1\" \/>\n<meta name=\"parsely-pub-date\" content=\"2026-09-01T14:00:00Z\" \/>\n<meta name=\"parsely-section\" content=\"Uncategorized\" \/>\n<meta name=\"parsely-tags\" content=\"agentic,generative ai,image\" \/>\n<meta name=\"parsely-author\" content=\"melindapham\" \/>","tracker_url":"https:\/\/cdn.parsely.com\/keys\/cloudinary.com\/p.js"},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1788284946\/Web_Assets\/blog\/Blog_Your_model_returns_a_file._Production_needs_an_asset\/Blog_Your_model_returns_a_file._Production_needs_an_asset.jpg?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/40356","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/87"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=40356"}],"version-history":[{"count":3,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/40356\/revisions"}],"predecessor-version":[{"id":40410,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/40356\/revisions\/40410"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/40408"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=40356"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=40356"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=40356"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}