If your AI SaaS pipeline includes media processing, transcription, or LLM scoring, the right background job architecture comes down to one question first: does your pipeline need native binaries or sustained CPU? If the answer is yes, plain serverless functions are risky, and you should choose a runner that can execute real containers or workers from day one. For most small teams on a Vercel + Supabase stack, the practical shortlist is Trigger.dev, BullMQ with a Redis worker, or Inngest/Upstash Workflow paired with a container runtime like Cloud Run. Supabase Edge Functions are good for lightweight server-side tasks, but they won't run FFmpeg.
What an AI SaaS background pipeline really does
A typical post-session pipeline in an AI-powered product looks something like this:
- Media ingestion. Audio or video files arrive from a recording session. They may need merging, format conversion, or normalization. FFmpeg is the standard tool.
- Transcription. The merged audio is sent to a speech-to-text API (AssemblyAI, Deepgram, Whisper, etc.). The API may take seconds or minutes. Some providers use webhooks; others require polling.
- LLM scoring or analysis. The transcript feeds into one or more LLM calls for scoring, summarization, entity extraction, or structured evaluation.
- Persistence and notification. Results are written back to the database. The user sees updated state in the UI. Downstream events (emails, Slack messages, analytics writes) may fire.
Each of these steps has different compute and latency characteristics. Media processing is CPU-bound and may need native binaries. Transcription is I/O-bound with unpredictable wait times. LLM calls can fail, rate-limit, or return partial results. Persistence is fast but must be idempotent.
A useful async processing pipeline tracks job state through fields like `queued`, `processing`, `waiting_transcription`, `scoring`, `complete`, and `failed`. It stores retry counts, external request IDs, and timestamps so you can debug failures without guessing.
This is where the distinction between orchestration and compute matters. Some tools coordinate steps (decide what runs next, handle retries, manage state). Others execute the actual work (run FFmpeg, call APIs, write to the database). Many products need both, and conflating them leads to architecture choices that break under real load.
Background job architecture options compared
Here's a comparison of the main options available to a team running a serverless frontend with managed data services.
| Option | Best fit | FFmpeg / native binaries | Ops burden | Main trade-off | |---|---|---|---|---| | Trigger.dev | Small teams needing containers + durable workflows | Yes, via FFmpeg build extension | Low (managed) | Vendor lock-in to Trigger.dev runtime | | Inngest + separate compute | Teams wanting portable orchestration | Only on the compute layer (Cloud Run, Lambda) | Medium | Two systems to configure and monitor | | Supabase Edge + pgmq/worker | Lightweight orchestration around a real worker | No. 2s CPU limit, no multithreading | Low-medium | Cannot handle CPU-bound work directly | | QStash / Upstash Workflow | Low-cost orchestration glue | No. Needs external compute for processing | Low | Each step and call generates billable messages; compute lives elsewhere | | BullMQ + Redis worker | Cost-sensitive teams comfortable with ops | Yes (full control of worker environment) | High | You own worker health, Redis, deploys, monitoring, retries, stalled-job handling | | AWS Lambda/Step Functions or Cloud Run | Teams already deep in cloud infrastructure | Yes (Lambda layers or container images) | Medium-High | Raises infrastructure surface area for a small team | | n8n | Internal business automation | Possible but not designed for it | Low | Not suited for product-critical, high-throughput execution |
The table makes one thing clear: there's no single tool that handles both orchestration and heavy compute for every team profile. Your choice depends on how much infrastructure you're willing to own.
Why FFmpeg changes the decision
FFmpeg is the dividing line in many AI SaaS backend decisions. If your pipeline merges audio tracks, converts formats, or normalizes media before sending it to a transcription API, you need FFmpeg or a similar native binary.
This rules out several otherwise-attractive options:
- Supabase Edge Functions run on Deno with a 256 MB memory cap and a 2-second CPU time limit. They can't spawn subprocesses or run native binaries like FFmpeg. They're fine for token minting, webhook validation, or lightweight data transforms.
- Standard serverless functions can become brittle once binary packaging, cold starts, and execution limits enter the picture. They may work for small experiments, but production media processing usually belongs in a container or worker.
- QStash / Upstash Workflow coordinates steps but doesn't provide compute. You still need somewhere to actually run FFmpeg.
Trigger.dev solves this directly. Its FFmpeg build extension installs a static FFmpeg 7.x binary into the task container and exposes `FFMPEG_PATH` and `FFPROBE_PATH`. You write your media processing logic in TypeScript, and the binary is available at runtime without Docker configuration on your side.
If you're using BullMQ with a self-managed worker, you install FFmpeg on the worker VM or container yourself. This works well but means you're responsible for the runtime environment, updates, and monitoring.
For teams evaluating FFmpeg in a serverless context, the practical advice is: don't fight the platform. If your serverless host can't run native binaries, move that work to a container-based runner and keep the serverless layer for what it does well.
How to choose a background job architecture
The decision framework has three layers.
1. What does the pipeline actually compute?
Map each step to its compute profile:
- CPU-bound with native binaries (FFmpeg, ImageMagick, Pandoc): needs a container or VM worker.
- I/O-bound with long waits (transcription webhooks, LLM API calls): needs durable workflow or checkpoint support so you're not paying for idle compute.
- Lightweight server-side logic (token minting, webhook validation, session setup): fine for Edge Functions or Next.js API routes.
2. How much infrastructure can the team own?
Be honest about this. A two-person team that ships a BullMQ + Redis worker will spend real hours on:
- Redis hosting and failover
- Worker deployment and health checks
- Stalled job detection and recovery
- Log aggregation and alerting
- Retry logic and dead-letter handling
If the team is infrastructure-comfortable and cost-sensitive, this is a strong option. If the team would rather ship product features, paying $50-$100/month for managed workflow execution can be cheaper than losing weeks on queue plumbing.
We saw this pattern in RAE Health, a wearable health monitoring platform we built over a 24+ month engagement. The product processes wearable signals, detects clinical events, and surfaces data to caregivers and providers through multiple portals. Early architecture decisions about async processing defined the ops burden for the life of the product. Choosing a managed, container-capable runner early would have reduced ongoing maintenance across the AWS-heavy backend.
3. Does the team need durable workflow semantics?
Durability means the system can survive failures, restarts, and long waits without losing progress. This matters when:
- A transcription API takes 90 seconds and you don't want to hold a function open the whole time.
- An LLM call fails on the third step of a five-step pipeline, and you need to retry from step three, not step one.
- A webhook arrives after the original function has timed out.
Trigger.dev handles this with checkpointing: waits longer than 5 seconds are checkpointed and don't count toward compute. Inngest handles it with step-based workflows where each step is independently retryable. BullMQ can approximate this with careful job chaining, but you build the durability yourself.
Recommended defaults
- Trigger.dev for most small teams building an AI SaaS backend with media processing. Lowest friction path to containers + durable workflows.
- BullMQ + Redis worker if the team can own operations and wants the lowest flat cost.
- Inngest or Upstash Workflow + Cloud Run if portability matters and compute needs are cleanly separated from orchestration.
- Supabase Edge Functions only for lightweight jobs or orchestration around a real worker.
- AWS Step Functions / Lambda / Cloud Run for teams already deep in cloud infrastructure.
- n8n only for internal business automation, not product-critical execution.
If you're building a product that combines media processing with AI analysis, our AI integration services team can help you design the pipeline architecture before you commit to a runner.
What the job layer really costs
AI API spend usually outweighs runner infrastructure by a wide margin. AssemblyAI charges $0.15-$0.21 per hour of audio for pre-recorded transcription before add-ons. If you're processing 500 interviews per month at 30 minutes each, that's 250 hours of audio, or $37.50-$52.50/month in transcription alone. LLM scoring adds more.
Here are rough planning estimates for the runner layer itself, excluding AI API charges. These come from our research model and will vary based on task duration, concurrency, and provider pricing changes:
| Architecture | ~500 jobs/month | ~5,000 jobs/month | |---|---:|---:| | Trigger.dev | ~$10 | ~$50 | | Inngest + Cloud Run | ~$99 | ~$106 | | Supabase Queues + small VPS worker | ~$30-32 | ~$35-50 | | BullMQ + Redis worker | ~$16-25 | ~$16-40 | | Upstash Workflow + Vercel + external media | ~$25 | ~$70 |
Trigger.dev's pricing page gives a concrete example: a 10-second task on a small-1x machine at 100 runs/day costs about $1.09/month. The checkpointing model means you're not paying for time spent waiting on external APIs.
The takeaway: don't over-optimize the runner cost. The difference between options is often $20-80/month. The difference in engineering time to set up and maintain them can be weeks. For teams choosing their MVP technology stack, this is a place where managed services earn their margin.
Where real-time session token minting belongs
If your product includes real-time sessions (live interviews, voice calls, video rooms), you'll need to mint session tokens for providers like Daily, LiveKit, or Twilio. This is a separate concern from the background pipeline.
Token minting is:
- Fast enough to run during the join flow
- Auth-sensitive because it verifies the requesting user
- Latency-sensitive because the user is waiting to join a session
Don't route this through your heavy job runner. Keep it in a Next.js API route or a Supabase Edge Function where it can execute close to your auth layer with minimal latency. The background pipeline handles what happens after the session ends.
For teams building real-time features alongside async pipelines, our guide on real-time voice AI providers covers the session-layer decisions in more detail.
Idempotency is not optional
Every step in your pipeline should be safe to retry. This sounds obvious, but it's the source of most production bugs in async systems:
- Double transcription charges. If a retry re-submits audio to AssemblyAI, you pay twice. Store the external request ID and check for an existing result before re-submitting.
- Double LLM scoring. If a retry re-runs scoring on the same transcript, you may overwrite a good result with a different one (LLM outputs aren't deterministic). Use a scoring version or hash to detect duplicates.
- Stale data overwrites. If step 4 retries and writes results while step 5 has already completed on a parallel path, you corrupt the final state. Use optimistic locking or version checks on writes.
Build idempotency keys into your job schema from day one. The cost of adding them later, after you've already double-billed a customer or corrupted a score, is much higher.




