FFmpeg is famously powerful, but its default mode of operation — a single command, on a single machine, with hard‑coded paths — doesn't scale. When you move from a one‑off conversion to a production pipeline, you quickly hit walls: inconsistent behaviour across environments, hours‑long rendering times, and manual intervention for every change.
FFmpegLab Server solves this with a complete, production‑grade architecture built on PostgreSQL, pgmq queues, S3‑compatible storage, and scalable runners. This guide walks you through the entire stack — from configuring environment variables to deploying a self‑hosted rendering cluster.
Key takeaways
- PostgreSQL + pgmq provides durable job queuing with transactional guarantees.
- S3‑compatible storage handles media assets and rendered output.
- Three runner types — render, file, and logs — each with specific responsibilities.
- Environment variables configure every aspect of the server and runners.
- Supabase serves as the full‑cycle provider for database, queues, storage, and API.
The Gap: One‑off Commands Don't Scale
Most FFmpeg tutorials teach you how to write a single command for a single file. That's fine for a quick conversion, but in production you face:
- Hundreds or thousands of files — each needing the same processing
- Different environments — development, staging, production
- Long processing times — a single 4K transcode can take hours
- Fragile commands — one wrong path and the whole job fails
- Team collaboration — multiple users need to submit and track renders
FFmpegLab Server's architecture solves these problems systematically.
The FFmpegLab Server Architecture
FFmpegLab Server is built on a modern, scalable architecture:
PostgreSQL
pgmq
S3 Storage
API Server
Render Runner
File Runner
Logs Runner
(Jobs are queued, processed asynchronously, and results stored in S3)
PostgreSQL (Projects, Renders, Users, Logs)
Powered by Supabase – Full‑Cycle Provider
FFmpegLab Server is built on Supabase — the open‑source Firebase alternative — as a full‑cycle provider for all backend services:
| Service | Provider | Description |
|---|---|---|
| PostgreSQL | Supabase | Primary database with Row Level Security (RLS) |
| pgmq | Supabase | Job queue for asynchronous render processing |
| S3‑compatible Storage | Supabase | File storage for media assets and rendered output |
| REST API | Supabase | Auto‑generated REST API with JWT authentication |
| API Keys | Supabase | User‑managed API keys with role‑based access |
| Logs | Supabase | Centralized storage of ffmpeg logs per render |
As one guide explains: "Supabase provides a full PostgreSQL database with authentication, storage, and real‑time subscriptions. It's the perfect backend for scalable applications".
FFmpegLab Server Environment Variables
FFmpegLab Server uses environment variables for complete configuration. Here's the full reference:
Database (PostgreSQL)
| Variable | Description | Required |
|---|---|---|
DB_HOST | PostgreSQL host | ✅ Yes |
DB_USER | PostgreSQL user | ✅ Yes |
DB_PORT | PostgreSQL port | ✅ Yes |
DB_PASSWORD | PostgreSQL password | ✅ Yes |
DB_NAME | PostgreSQL database name | ✅ Yes |
DB_MIGRATION_ENABLED | Auto‑run database migrations | ⚠️ Optional (default: false) |
Queue Database (pgmq)
The queue database can be the same as the main database or a separate instance.
| Variable | Description | Required |
|---|---|---|
QUEUE_DB_HOST | Queue PostgreSQL host | ✅ Yes |
QUEUE_DB_USER | Queue PostgreSQL user | ✅ Yes |
QUEUE_DB_PORT | Queue PostgreSQL port | ✅ Yes |
QUEUE_DB_PASSWORD | Queue PostgreSQL password | ✅ Yes |
QUEUE_DB_NAME | Queue PostgreSQL database name | ✅ Yes |
S3 Storage
Required for the file-runner service.
| Variable | Description | Required |
|---|---|---|
S3_ACCESS_KEY | S3 access key | ⚠️ For file-runner |
S3_SECRET_KEY | S3 secret key | ⚠️ For file-runner |
S3_REGION | S3 region (e.g., us-east-1) | ⚠️ For file-runner |
S3_ENDPOINT | S3 endpoint URL | ⚠️ For file-runner |
Runner Mode Flags
These flags determine which runner mode the service runs in.
| Variable | Description | Required |
|---|---|---|
IS_RENDER_RUNNER | Enable render runner mode | ⚠️ For render-runner |
IS_FILE_RUNNER | Enable file runner mode | ⚠️ For file-runner |
IS_LOGS_RUNNER | Enable logs runner mode | ⚠️ For logs-runner |
Data Models
The server uses TypeORM with models defined in src/models/:
Project— Editor project storage and configurationRender— Render job tracking and statusApiKey— API key management with permissionsLogPiece— Render Logs
Docker Compose Configuration
The repository includes a docker-compose.yml that defines all services:
services:
api:
image: ffmpeglab/server:latest
ports: - "3000:3000"
environment:
- DB_HOST=${DB_HOST}
- DB_USER=${DB_USER}
- DB_PORT=${DB_PORT}
- DB_PASSWORD=${DB_PASSWORD}
- DB_NAME=${DB_NAME}
- QUEUE_DB_HOST=${QUEUE_DB_HOST}
- QUEUE_DB_NAME=${QUEUE_DB_NAME}
- DB_MIGRATION_ENABLED=${DB_MIGRATION_ENABLED}
render-runner:
image: ffmpeglab/server:latest
environment:
- DB_HOST=${DB_HOST}
- DB_USER=${DB_USER}
- DB_PASSWORD=${DB_PASSWORD}
- DB_NAME=${DB_NAME}
- QUEUE_DB_HOST=${QUEUE_DB_HOST}
- QUEUE_DB_NAME=${QUEUE_DB_NAME}
- IS_RENDER_RUNNER=true
file-runner:
image: ffmpeglab/server:latest
environment:
- DB_HOST=${DB_HOST}
- S3_ACCESS_KEY=${S3_ACCESS_KEY}
- S3_SECRET_KEY=${S3_SECRET_KEY}
- S3_REGION=${S3_REGION}
- S3_ENDPOINT=${S3_ENDPOINT}
- IS_FILE_RUNNER=true
logs-runner:
image: ffmpeglab/server:latest
environment:
- DB_HOST=${DB_HOST}
- DB_USER=${DB_USER}
- DB_PASSWORD=${DB_PASSWORD}
- DB_NAME=${DB_NAME}
- IS_LOGS_RUNNER=true
Start the complete stack:
View the logs:
Scalable Runners – The Engine
Runners are workers that execute jobs from the pgmq queue. The magic happens when you have multiple runners working in parallel.
How Runners Work
- The API server receives a rendering request and pushes a job to the pgmq queue.
- One or more render-runners poll the queue for new jobs.
- Each runner picks up a job, executes FFmpeg with the provided parameters, and uploads the result to S3 storage.
- The runner updates the job status in the database, and the client polls for completion.
Runner Types
| Runner | Flag | Responsibility |
|---|---|---|
| Render Runner | IS_RENDER_RUNNER | Executes FFmpeg rendering jobs from the queue |
| File Runner | IS_FILE_RUNNER | Handles file operations with S3 storage |
| Logs Runner | IS_LOGS_RUNNER | Processes and stores system and user activity logs |
As noted in the broader FFmpeg ecosystem: "You can create multiple runners and distribute the workload, significantly reducing processing time for large workloads".
Scaling the Rendering Pipeline
The queue‑based architecture makes scaling straightforward:
- Add more render-runners — spin up additional
render-runnerinstances to process jobs in parallel - Autoscaling — runners can be configured to autoscale based on queue depth
- GPU acceleration — runners can be deployed on GPU‑enabled instances for faster rendering
- Separate queues — use different queues for different job types or priorities
Scaling command:
This spins up 8 render-runner instances, all pulling from the same pgmq queue.
Security Considerations
- Database credentials — keep
DB_PASSWORDandQUEUE_DB_PASSWORDsecure. Never commit them to version control. - S3 credentials —
S3_ACCESS_KEYandS3_SECRET_KEYshould be treated as secrets. - API Keys — the server manages API keys with role‑based access via the
ApiKeymodel. - Row Level Security — Supabase RLS policies ensure users can only access their own data.
- Logs — the
LogsModelprovides structured logging with retention policies.
Frequently Asked Questions (FAQ)
What is the difference between render-runner, file-runner, and logs-runner?
render-runner executes FFmpeg rendering jobs from the queue. file-runner handles S3 file operations (upload, download, delete). logs-runner processes and stores system and user activity logs. They can all run on the same machine or be distributed across multiple machines.
Can I use the same PostgreSQL instance for both the database and the queue?
Yes. You can set QUEUE_DB_HOST and QUEUE_DB_NAME to the same values as DB_HOST and DB_NAME. They can be the same database or separate databases on the same server.
What S3-compatible storage services work with FFmpegLab Server?
Any S3-compatible storage works: Supabase Storage, AWS S3, MinIO, Cloudflare R2, Backblaze B2, or any other S3‑compatible endpoint. The S3_ENDPOINT variable lets you specify your provider's endpoint.
How do I scale the rendering pipeline?
Scale by adding more render-runner instances. Each runner pulls from the same pgmq queue, enabling parallel processing. You can use docker compose up -d --scale render-runner=8 or orchestrate with Kubernetes.
What database models does FFmpegLab Server use?
The server uses TypeORM with models defined in src/models/: Project (editor projects), Render (render jobs), User (user profiles), ApiKey (API key management), and Log (render logs).
Final Word
Environment variables and scalable runners turn FFmpegLab Server into a production‑grade media processing platform. With PostgreSQL for storage, pgmq for job queuing, S3‑compatible storage for assets, and three types of scalable runners, you can handle workloads that would be impossible with one‑off commands.
The key components work together seamlessly:
- PostgreSQL — persistent storage for projects, renders, and users
- pgmq — durable job queue with transactional guarantees
- S3 Storage — media assets and rendered output
- API Server — REST API with JWT authentication
- Render Runner — scalable workers that execute FFmpeg
- File Runner — S3 file operations
- Logs Runner — structured log processing
- Environment variables — parameterize everything for portability and reproducibility
Next time you're facing a mountain of media files, remember: you don't have to process them one by one. Scale up with FFmpegLab Server.