ffmpegself-hostingvideo-api

The NCA Toolkit is free. Self-hosting it isn't cheap.

·Javid Jamae·10 min read
The NCA Toolkit is free. Self-hosting it isn't cheap.

Every time an n8n builder asks how to process video without a monthly bill, somebody links stephengpope/no-code-architects-toolkit. It's a good answer. It's also an answer with an operations bill nobody publishes, and you meet that bill the first time a 6-minute render dies on Cloud Run.

Quick answer: The NCA Toolkit is a free, self-hostable Docker container that bundles FFmpeg composition, transcription, and captioning behind a single API key, and it runs fine on Google Cloud Run for jobs that finish in under 5 minutes. What it costs instead of money is operations: an S3 or GCS bucket plus API key before your first request works, GUNICORN_TIMEOUT and MAX_QUEUE_LENGTH tuning once real traffic arrives, temp files that count against instance memory, and a container you rebuild yourself every time FFmpeg ships a security fix. If you'd rather not own an encoder, FFmpeg Micro runs the same jobs as one API call with no servers to run and 50 free processing minutes to test it.

The NCA Toolkit earns its reputation

The toolkit is genuinely good software, and dismissing it means you haven't used it. One container gives you /v1/ffmpeg/compose for arbitrary filter graphs, /v1/media/transcribe, /v1/video/caption, /v1/video/concatenate, /v1/video/thumbnail, /v1/image/convert/video, and about a dozen more, all behind a single x-api-key header. That's 2.3k stars and 975 forks worth of consolidation work you don't have to do.

It arrived at the right moment. n8n disabled the Execute Command node by default in v2.0 because arbitrary shell execution is a liability in shared instances, so the old "shell out to FFmpeg" workaround stopped working for most builders. A self-hosted HTTP endpoint you control is the natural replacement, and per-minute vendor pricing feels absurd when you're rendering 200 clips a night.

The question isn't whether the toolkit works. It's what the free part costs you.

Cloud Run's 5-minute wall is the first real cost

The toolkit's README recommends Google Cloud Run and names the limit in the same breath: Cloud Run terminates long-running processes, so it's best for consistent processing under 5 minutes. That's not a bug in the toolkit. It's what happens when you put a batch workload on a request-response platform.

Five minutes of wall clock is less than it sounds. A 4-minute 1080p source that needs a filter graph and a libx264 re-encode can easily run past its own duration on 2 vCPUs. Cloud Run also scales to zero, which is why it's cheap, so add 10 to 30 seconds of cold start booting a multi-gigabyte image with FFmpeg and transcription models inside.

Digital Ocean's App Platform isn't a free escape either. Its CloudFlare proxy imposes a 1-minute synchronous timeout, so anything longer has to pass webhook_url and go async. Workable, but your n8n workflow now needs a callback path, a waiting node, and somewhere to correlate the job ID.

The 30-second timeout that trips people first

Before Cloud Run's limit ever bites, GUNICORN_TIMEOUT will. The toolkit's default worker timeout is 30 seconds, so a job that takes 45 seconds gets its worker killed by the app server, not the platform, and the error you see has nothing to do with video. Raising it is one env var. Knowing to raise it costs you an evening.

Temp files on Cloud Run come out of your RAM

LOCAL_STORAGE_PATH defaults to /tmp, and on Cloud Run /tmp is an in-memory filesystem. Every intermediate file FFmpeg writes there is charged against the instance's memory limit, so a container sized at 2 GiB that downloads a 400 MB source, writes a 500 MB intermediate, and muxes a 350 MB output is competing with itself. The symptom is an out-of-memory kill that looks random because it depends on input size. The fix is a bigger memory allocation or a real volume mount.

What you configure before request number one

The toolkit needs storage wired up before it returns anything useful, because it hands back URLs, not bytes. That means either the S3-compatible set (S3_ENDPOINT_URL, S3_ACCESS_KEY, S3_SECRET_KEY, S3_BUCKET_NAME, S3_REGION) or the Google path (GCP_SA_CREDENTIALS, GCP_BUCKET_NAME), plus a mandatory API_KEY you generate and store yourself.

Budget an afternoon for the parts nobody writes down: creating the service account, scoping the bucket IAM so the container can write but the internet can't, deciding whether outputs are public or presigned, setting a lifecycle rule so renders don't accumulate forever, and getting GCP_SA_CREDENTIALS into Cloud Run as a secret, not a plaintext env var. None of it is hard. All of it is yours.

Then there's throughput. GUNICORN_WORKERS defaults to CPU cores plus one, a sensible default for a web app and a bad one for FFmpeg, because every worker running an encode wants all the cores. Over-provision workers and jobs slow each other down until they hit the timeout. MAX_QUEUE_LENGTH is unlimited by default, so a burst from a Google Sheets trigger accepts 300 jobs your instance can't finish before the requests die. Tuning those two against your real clip lengths is the actual operations work, and you redo it whenever your workload changes.

Somebody has to patch the container

FFmpeg is a large C codebase that parses hostile input, and it gets CVEs. When one lands in a demuxer you use, the update path on a self-hosted toolkit is: notice, rebuild the image, redeploy, verify nothing regressed. On a managed API, the path is: nothing. That difference costs zero dollars and shows up as an open browser tab you keep meaning to deal with.

This is the honest trade, and it's the same one behind skipping a media microservice inside a SaaS product: running the encoder is easy, keeping it running is the job.

The same watermark job, both ways

Stamping a creator ID onto a clip is a good test: both systems do it, and the difference is all in what you have to know. The NCA Toolkit has no watermark endpoint, so you build the filter graph yourself and post it to /v1/ffmpeg/compose:

curl -X POST https://your-nca-host/v1/ffmpeg/compose \
  -H 'x-api-key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "inputs": [{ "file_url": "https://cdn.example.com/clip.mp4" }],
    "filters": [{
      "filter": "drawtext=text=@creator_8842 | id 5f21:fontsize=36:fontcolor=white:borderw=6:x=w-tw-48:y=h-th-48"
    }],
    "outputs": [{ "options": [
      { "option": "-c:v", "argument": "libx264" },
      { "option": "-crf", "argument": 23 }
    ]}],
    "webhook_url": "https://your-n8n/webhook/nca-done",
    "id": "clip-8842"
  }'

That's real FFmpeg. You own the x/y expressions, the escaping rules that make drawtext miserable when the text contains a colon, and the outputs land in your own bucket. The same job on FFmpeg Micro is a named option instead of a filter string:

curl -X POST https://api.ffmpeg-micro.com/v1/transcodes \
  -H "Authorization: Bearer $FFMPEG_MICRO_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "inputs": [{ "url": "https://cdn.example.com/clip.mp4" }],
    "outputFormat": "mp4",
    "options": [
      { "option": "-c:v", "argument": "libx264" },
      { "option": "-crf", "argument": "23" },
      { "option": "@text-overlay", "argument": {
          "text": "@creator_8842 | id 5f21",
          "style": { "position": "bottom-right", "fontSize": 36, "outlineThickness": 6, "margin": 48 }
      }}
    ]
  }'

Then poll GET /v1/transcodes/JOB_ID until status is completed and take outputUrl. Raw FFmpeg options still pass through, so you haven't lost the escape hatch. For logo stamping rather than text, the watermark blueprint is the same job with position and size as form fields, and the longer watermarking walkthrough covers UGC.

Common pitfalls when self-hosting the toolkit

Five self-hosting mistakes eat the most time, in roughly the order builders hit them.

  1. Deploying to Cloud Run, testing with a 20-second clip, then shipping 8-minute podcast videos to it. Test with your longest real input, not a sample.
  2. Leaving GUNICORN_TIMEOUT at 30 and reading the resulting 502 as a network problem.
  3. Sizing memory for FFmpeg and forgetting that /tmp writes land in that same memory on Cloud Run.
  4. Pushing files through n8n instead of URLs. Reading a 1 GB render back into an n8n node is a known way to kill the instance, no matter which backend renders it. Pass URLs, take a webhook. The end-to-end n8n clip workflow has that shape.
  5. Assuming synchronous responses will keep working as clips get longer. Wire webhook_url from day one, even on Cloud Run.

Stay on the NCA Toolkit if these are true

The toolkit is the right call more often than a vendor blog usually admits. Keep it if you have steady, predictable jobs under about 4 minutes, you already run containers and have a bucket and an IAM story, your volume is high enough that per-minute pricing genuinely hurts, or you need the local transcription and captioning stack in the same box as the encoder. Also keep it if you like owning your stack. Self-hosting is the only way to get that.

The honest cost picture side by side:

NCA Toolkit, self-hostedFFmpeg Micro
Money per minute of videoCloud Run CPU and memory seconds, roughly a cent a minute of active processing, plus bucket storage and egress3 tokens per 10 seconds of input, about 139 minutes on the $19.99 Starter plan
Setup before first jobAPI key, bucket, IAM, deploy, worker tuningAPI key
Long jobsCapped by the host: about 5 minutes on Cloud Run, 1 minute synchronous on Digital OceanSubmit, poll or webhook, no host limit to tune
ConcurrencyYou tune `GUNICORN_WORKERS` and `MAX_QUEUE_LENGTH`Managed
FFmpeg CVEsYou rebuild and redeployManaged
Free to startYes, minus your time50 processing minutes

Raw compute on your own Cloud Run instance is cheaper per minute than any managed API, including this one. That's the real trade, and the pricing comparison page has the full math. What you're buying with the difference is the 5-minute wall never becoming your problem, and never being the person who redeploys the encoder at 11pm.

FAQ

What is the NCA Toolkit?

The NCA Toolkit is a free, open-source Docker container from the No-Code Architects community that exposes FFmpeg composition, media conversion, transcription, captioning, and image-to-video behind a REST API secured with an x-api-key header. Builders self-host it on Google Cloud Run, Digital Ocean, or any Docker host so their n8n, Make, or Zapier workflows can process video without a per-render subscription.

Why does the NCA Toolkit time out on Cloud Run?

Two separate limits cause NCA Toolkit timeouts on Cloud Run. The toolkit's own GUNICORN_TIMEOUT defaults to 30 seconds and kills the worker first, and Cloud Run itself terminates long-running processes, which is why the README recommends it only for processing that consistently finishes under 5 minutes. Raise GUNICORN_TIMEOUT, then move anything longer to an async webhook_url pattern.

Is the NCA Toolkit really free?

The NCA Toolkit software is free and the code is public, but running it is not. You pay Google Cloud Run or your VPS for compute, a bucket for storage and egress, and your own hours for IAM setup, worker tuning, memory sizing, and rebuilding the image whenever FFmpeg ships a security fix.

What's a good NCA Toolkit alternative for long videos?

For jobs that run past Cloud Run's 5-minute window, a managed video API removes the host timeout entirely instead of working around it. FFmpeg Micro takes the same FFmpeg options you'd write in a compose request, returns a job ID you poll or get a webhook for, and has no container for you to size or patch.

Can I use both?

Running both is common. Teams keep the NCA Toolkit for short, high-volume jobs where self-hosted compute is cheapest, and route long renders or anything customer-facing to a managed API so a cold start or an OOM kill never reaches a user.

To see how your actual clips behave without deploying anything, the free tier gives you 50 processing minutes and an API key in about a minute. Run your longest video through both and compare what you get back.

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