Sortarr
Sortarr is a self-hosted Jellyfin media organizer and dashboard. It watches /downloads, plans safe Jellyfin-friendly moves, chooses one of four mounted media drives, exposes storage, downloads, and library state, and ships with a fully editable vanilla dashboard.
The project is intentionally source-first: backend logic is plain Python, the UI is HTML/CSS/JS, and runtime behavior is configured with .env, TOML config files, and optional CSS overrides.
Quick Start
-
Copy the environment template:
cp .env.example .env -
Edit
.envand setDOWNLOADS_PATH,DRIVE1_PATH,DRIVE2_PATH,DRIVE3_PATH, andDRIVE4_PATH. -
Review
config/app.toml. KeepSORTARR_DRY_RUN=trueuntil the generated plans look right. -
Start the stack:
docker compose up --build -
Open
http://localhost:8088.
Production mode:
docker compose -f compose.yaml -f compose.prod.yaml up -d --build
Optional profiles:
docker compose --profile cache up -d
docker compose --profile database up -d
docker compose --profile tools up -d
Services
web: nginx serving the editable dashboard fromweb/src.backend: Python API plus 24/7 worker loop.redis: optional cache profile for future workflow extensions.postgres: optional database profile for installations that outgrow JSON state.media-tools: optional ffmpeg tools container.
Mounted Host Paths
/downloads: incoming files./media/drive1through/media/drive4: Jellyfin media drives./config: TOML config and custom CSS./logs: rotating backend logs./data: JSON state and scan history.
Safety Model
Sortarr defaults to dry-run mode. In dry-run mode it scans, parses, chooses drives, computes destination paths, and records planned actions without moving files.
When dry-run is disabled, moves use a temporary .sorting destination before the final rename. Existing destinations follow the configured collision rule: keep-both, skip, or replace.
Permissions
The default Compose file runs the backend with the container default user so a fresh checkout can create logs, state, and media folders without a bootstrap script. On a hardened media host, set ownership on the mounted paths and add a user: "${SORTARR_UID}:${SORTARR_GID}" line to the backend service in a local override.
Customization
Edit these files directly:
config/app.toml: runtime organizer rules and provider settings..env: deployment paths, ports, and intervals.backend/sortarr/*.py: parsing, drive choice, scanner, API, provider integrations.web/src/*.html,*.css,*.js: dashboard layout, styling, themes, routes.config/custom-theme.css: host-side CSS variable overrides loaded at runtime.
See docs/configuration.md, docs/api.md, and docs/operations.md.