VOD Docs

Configuration

Every backend setting, its default, and how configuration reaches the containers.

Settings are a Pydantic BaseSettings class (backend/app/core/config.py), read from environment variables and cached with lru_cache, so every module shares one instance via get_settings(). Matching is case-insensitive: JWT_SECRET_KEY and jwt_secret_key both set the same field.

How values reach the code

Flow diagram · placeholder
Configuration flow: infra/*.env → Docker Compose env_file → container environment → pydantic Settings

Show that the API and worker read the same env file, and that some services (Postgres, Redis, MinIO) take values through compose variable substitution instead.

  1. Each environment has an env file in infra/ (local.env, prod.env), created from infra/.env.example. Env files are git-ignored.
  2. Docker Compose passes it to the api and worker containers with env_file.
  3. Infrastructure containers (PostgreSQL, Redis, MinIO, tusd) get their values through compose variable substitution, so compose must be run with --env-file.

Fields marked required have no default: the API and worker refuse to start if they are missing.

Database and Redis

SettingDefaultPurpose
database_url_syncrequiredSQLAlchemy URL (postgresql://…, psycopg2), also used by Alembic
database_urlrequiredAsync URL; currently unused
redis_hostrequiredRedis host
redis_passwordrequiredRedis password
redis_port6379
redis_db0Celery broker and result backend share this database

Auth and email

SettingDefaultPurpose
jwt_secret_keyrequiredHMAC signing key
jwt_algorithmrequiredFor example HS256
access_token_expire_minutes30Access-token lifetime
refresh_token_expire_days7Refresh-token lifetime
RESEND_API_KEYrequiredEmail provider key
from_emailrequiredSender address
FRONTEND_URLrequiredBase for links in emails (verification)
CORS_ALLOW_ORIGINShttp://localhost:3000, http://127.0.0.1:3000Comma-separated allowed origins (read directly from the environment in main.py)

Storage

SettingDefaultPurpose
minio_endpointrequiredhost:port of MinIO
minio_access_key, minio_secret_keyrequiredCredentials
minio_bucket_videosrequiredRaw uploads
minio_bucket_thumbnailsrequiredPosters and storyboards
minio_bucket_processed_videosrequiredHLS output
minio_securefalseTLS between the backend and MinIO (internal traffic)

Buckets are created automatically if they do not exist when the backend starts.

Processing

SettingDefaultPurpose
FFMPEG_THREADS2-threads passed to each FFmpeg encode
QUALITY_SETTINGS2160p…144p tableThe bitrate ladder (HLS output)
processing_temp_dir<backend>/tmp/video_processingWorker scratch space

Celery itself is configured in backend/app/celery_app.py: JSON serialisation, task_track_started, results kept 24 hours, a 50-minute soft and 60-minute hard time limit per task.

Uploads

SettingDefaultPurpose
max_video_size, max_thumbnail_sizerequiredDeclared size limits (must be present in the env file)
uploads_tus_enabledtrueResumable-upload hooks on or off
tus_part_size_mb50S3 part size for tusd
tus_max_concurrent_uploads8Admission cap
tus_max_file_size_gb50Maximum declared size
tus_allowed_mime_typesmp4, quicktime, webmAccepted video types
tus_admission_ttl_hours2Expiry of an admission slot
tus_hook_shared_secretemptyAuthenticates tusd hook calls

Frontend

The frontend reads two build-time variables:

VariablePurpose
NEXT_PUBLIC_API_URLBase URL of Caddy (API and /storage)
NEXT_PUBLIC_UPLOADS_TUS_ENABLEDfalse switches the upload page to the legacy form

NEXT_PUBLIC_* values are inlined into the JavaScript bundle at build time, so changing them requires a rebuild.

On this page