ffmpegvideo-apisaas

Skip the Media Service: Video Processing API for a SaaS Product

·Javid Jamae·10 min read
Skip the Media Service: Video Processing API for a SaaS Product

Your product needs three video endpoints: compress an upload, pull a thumbnail, burn in captions. Somewhere between the spec doc and the second sprint, that turns into a queue, a worker pool, an S3 bucket, a retry policy, and a static FFmpeg binary you now maintain.

Quick answer: A video processing API for SaaS products replaces the media microservice you'd otherwise build: instead of packaging FFmpeg into an AWS Lambda layer or running a Fargate task pool, your backend POSTs a job to a hosted endpoint and gets a webhook when the output is ready. The DIY path works, but a static FFmpeg build plus a queue plus object storage is roughly three weeks of engineering and $120 a month in idle AWS cost before you process a single customer video. FFmpeg Micro runs the same FFmpeg operations as one API call, with no servers to run and a free tier to test against.

Conventional wisdom says video processing is infrastructure, and infrastructure belongs in your infrastructure. Most teams that follow it end up with a working media service, so the belief isn't wrong. What hurts later isn't the compute bill or the FFmpeg command. It's that you've added a second product to your roadmap, one your customers will never see and your on-call rotation will never stop hearing from.

Build vs buy for video, decided in five questions

The build-vs-buy call on video processing comes down to whether media handling is a feature of your product or the product itself. If you're selling analytics, scheduling, or CRM software and video is one step in a workflow, buying wins on almost every axis. If you're selling video, the encoder is your margin and you should own it.

Five questions settle it faster than a spreadsheet:

  1. Is the video pipeline something a customer would pay more for if it were better? If no, it's plumbing.
  2. Does any job run longer than 15 minutes of wall-clock encoding? That's the Lambda ceiling, and it decides your whole architecture.
  3. Do you need codec or filter behavior a hosted API doesn't expose, like a custom build with a patched filter?
  4. How spiky is the load? Ten uploads a day and 400 on launch day is a scaling problem you'd solve from scratch.
  5. Who fixes it at 2 a.m. when a customer's iPhone HEVC file makes the worker OOM?

A two-person analytics SaaS shipped "export your dashboard as a narrated video" in four days using a hosted API. The version they'd scoped in-house was a three-week ticket, and that estimate didn't include the CloudWatch alarms.

What a media microservice actually costs

The real cost of running your own FFmpeg service is the operational surface, not the CPU. Compute is the cheapest line item. What accumulates is version drift, timeout handling, storage lifecycle rules, and the knowledge of why your Dockerfile pins a 2023 build.

FFmpeg on Lambda hits three hard walls

AWS Lambda is the first idea everyone has, and it works right up until it doesn't. A function plus its layers is capped at 250 MB unzipped, and a static amd64 FFmpeg build from the common John Van Sickle tarball puts ffmpeg and ffprobe at roughly 78 MB each. You'll fit, but not comfortably, which is why most teams end up on container images.

The 15-minute execution ceiling is the wall that breaks products. A 45-minute webinar re-encoded at -preset medium will not finish, and no flag fixes it. You either chunk the input and concatenate the outputs, which is its own subsystem, or you move off Lambda.

The third wall is /tmp. Default ephemeral storage is 512 MB, configurable up to 10 GB, and FFmpeg wants scratch space for two-pass encoding, palette generation, and any filter graph that buffers. Getting the sizing wrong produces a "No space left on device" error nobody reads until a customer complains.

ECS and Fargate move the problem instead of removing it

Amazon ECS on Fargate solves the timeout and gives you real disk, and in exchange you get a cost floor and a patching schedule. A single 2 vCPU / 4 GB Fargate task running continuously in us-east-1 is about $59 in vCPU time and $13 in memory per month at on-demand rates, call it $72. Add a NAT gateway at roughly $32 a month and an Application Load Balancer at $17, and the idle floor is close to $120 before any video moves.

Fargate also can't attach a GPU. If NVENC hardware encoding is on your roadmap, you're back to the EC2 launch type, which means AMIs, driver versions, and capacity planning. The container is the easy part, as anyone who has shipped FFmpeg in Docker knows.

What you handleFFmpeg on LambdaFFmpeg on ECS/FargateHosted video API
FFmpeg install and version pinningYouYouManaged
Max job length15 minutesUnboundedUnbounded
Idle monthly cost~$0~$120 (task + NAT + ALB)$0 on the free tier
Burst concurrencyAutomatic, with cold startsYou size the task poolAutomatic
Scratch disk sizing512 MB to 10 GB, your callYou provisionNot your problem
Time to a working endpoint1 to 3 weeks2 to 4 weeksUnder 30 minutes
On-call surfaceYour rotationYour rotationVendor's

Wire a one-call media endpoint into your backend

Adding video to a SaaS backend without a media microservice takes three moving parts: a POST that submits the job, a webhook route that receives the result, and a column that stores the output URL.

The compression job as raw FFmpeg, the way you'd run it on a box you own:

ffmpeg -i input.mp4 -c:v libx264 -crf 26 -preset veryfast \
  -c:a aac -b:a 128k -movflags +faststart output.mp4

That command works, and it's what your worker would shell out to. The same job as a hosted call, from anywhere your backend already makes HTTP requests:

curl -X POST https://api.ffmpeg-micro.com/jobs \
  -H "Authorization: Bearer $FFMPEG_MICRO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "input": "https://uploads.yourapp.com/raw/abc123.mp4",
    "operation": "compress",
    "webhook": "https://api.yourapp.com/hooks/video"
  }'

Operation names and per-operation options are in the docs. You submit, you poll or take a webhook, you download the output.

Send the job from your existing request handler

Your upload handler already writes a row and returns a 202. Add the job submission next to it, store the returned job ID on the record, then return immediately. Never wait for the encode inside an HTTP request: Heroku kills any request still open at 30 seconds with an H12 error, and most managed platforms have a similar router timeout.

Take the webhook and update the row

Your webhook route does two things: verify the request came from the API, then update the media row with the output URL and a ready status. That's the entire integration for the happy path. Anything more complex, like four platform variants from one source, is the same call with different options, the pattern behind encoding a video once for every platform.

Serve the output from your own storage

Copy finished files into your bucket if your product needs permanent URLs under your domain. A background job that writes the output to S3 or Cloudflare R2 keeps the vendor out of your customer-facing URLs and makes swapping providers a one-file change.

Pitfalls that show up in week two

Most failures in a video-backed SaaS feature are integration bugs, not encoding bugs. The ones that reliably bite:

  • Presigned input URLs that expire in 60 seconds. A queued job that starts eight minutes later gets a 403, and the error looks like a codec problem in your logs.
  • No idempotency on webhook delivery. Retries are normal; a duplicate delivery that appends a second output row will happen in your first month.
  • Trusting the client's stated file type. Run ffprobe on the input or let the API reject it, because "video.mp4" is sometimes a MOV with a rotation matrix that flips your thumbnails sideways.
  • Storing video bytes in Postgres. It works at 20 files and stops working at 2,000.
  • Skipping -movflags +faststart on anything played in a browser. Without it the moov atom sits at the end of the file and playback stalls until the whole thing downloads.

When you should build the media service yourself

Owning the encoder is the right call in a few real cases. If your product's core value is the transform itself, a color grading tool, a codec research product, a broadcast pipeline with frame-accurate compliance requirements, then the encoder is your competitive surface and belongs in-house.

Two other cases favor building. Regulated data that can't leave your VPC rules out any hosted processor, full stop. And enormous steady-state volume, thousands of hours a day with flat demand, eventually makes reserved EC2 with NVENC cheaper per minute than any per-call price, though that crossover is much further out than most teams assume. Anything below that, including most batch work like transcoding a whole folder on a schedule, is cheaper to buy than to run.

FAQ

What's the fastest way to add video transcoding to a web app without a server?

Calling a hosted video processing API from your existing backend and taking a webhook when the job finishes is the fastest path. No queue, no worker pool, and no FFmpeg binary in your deploy artifact. The integration is one POST route and one webhook route, under 30 minutes of work in Node.js, Python, Ruby, or Go.

Can I just run FFmpeg on AWS Lambda for a SaaS product?

You can run FFmpeg on AWS Lambda, and it's a reasonable fit for short jobs like thumbnail extraction where the input is under a minute. It breaks on the 15-minute execution ceiling, the 250 MB unzipped package limit for a function plus layers, and cold starts on a 78 MB static binary. Longer jobs need ECS, Fargate, or a hosted API.

How much does a media microservice cost to run?

A minimal always-on media microservice on AWS Fargate costs roughly $120 a month at idle: about $72 for a 2 vCPU / 4 GB task, $32 for a NAT gateway, and $17 for a load balancer. The larger cost is engineering time, two to four weeks to build plus recurring maintenance for FFmpeg upgrades and failure handling.

Does a video processing API work with n8n or Make instead of custom code?

FFmpeg Micro works from n8n, Make, and Zapier using a plain HTTP request node, so a team without a backend can wire the same jobs into an automation. The job semantics match the API path: submit, wait for the webhook, use the output URL. There's also an MCP server if you want AI agents calling video operations as a tool.

What happens when the input file is corrupt or the request is malformed?

A malformed job request comes back as a 4xx with the failing field named, so you can surface a useful message instead of a generic failure. A corrupt or unreadable input fails the job itself and reports through the same webhook with an error status, so your application handles both cases in the code path you already wrote.

Spin up an API key and send your first compress job against the free tier before you write the design doc for a worker pool. The per-call cost model is on the pricing page if the numbers matter to your build-vs-buy math.

About Javid Jamae

Founder & CEO at FFmpeg Micro

Javid is a software engineer, author, and entrepreneur with over 25 years of professional software development experience across enterprise, startup, and consulting environments. He founded FFmpeg Micro to make video processing accessible to developers through a simple, automation-first REST API.

Software EngineeringVideo ProcessingFFmpegCloud ArchitectureAPI DesignAutomation

Ready to process videos at scale?

Start using FFmpeg Micro's simple API today. No infrastructure required.

Get Started Free