Founded in 2021 - real human work, before mainstream AI.
Maintainerr is the janitor your media server doesn't have.
Libraries fill up. Users request a movie, watch it once, and never touch it again. Half-finished shows sit around for years. And somehow you're the one who has to decide what to delete.
Maintainerr does the deciding for you. Write rules for the stuff that's just taking up space - unwatched, unrequested, gathering dust - and it gathers those titles into a collection, gives everyone a grace period to catch up, then clears them from your media server, the *arrs and Seerr. Set it up once and forget it. Everything is automated!
Docker images for amd64 & arm64 are available from:
Data directory. Maintainerr stores its data at
/opt/datainside the container. Mount a persistent volume there in yourdocker runcommand or Compose file. The directory must be readable and writable by the configureduser; if nouseris set, make it accessible to UID:GID1000:1000.
If you set
BASE_PATH, add it to the start of the paths too (e.g./maintainerr/api/health/ready).
For more information, visit the installation guide.
Docker run
docker run -d \
--name maintainerr \
-e TZ=Europe/Brussels \
-v ./data:/opt/data \
-u 1000:1000 \
-p 6246:6246 \
--restart unless-stopped \
ghcr.io/maintainerr/maintainerr:latestDocker Compose
services:
maintainerr:
image: ghcr.io/maintainerr/maintainerr:latest # or ghcr.io/maintainerr/maintainerr:development (to test unreleased changes)
container_name: maintainerr
user: 1000:1000
volumes:
- type: bind
source: ./data
target: /opt/data
environment:
- TZ=Europe/Brussels
# - BASE_PATH=/maintainerr # uncomment if you're serving maintainerr from a subdirectory
# - UI_HOSTNAME=:: # uncomment if you want to listen on IPv6 instead (default 0.0.0.0)
# - UI_PORT=6247 # uncomment to change the UI port (default 6246)
# - GITHUB_TOKEN=ghp_yourtoken # Optional: GitHub Personal Access Token for higher API rate limits (60/hr without, 5000/hr with token)
ports:
- 6246:6246
restart: unless-stopped
healthcheck: # already baked into the image; included here so you can tune it
test: ['CMD', '/opt/app/healthcheck.sh']
interval: 30s
timeout: 5s
start_period: 40s
retries: 3Kubernetes (Deployment + Service)
apiVersion: apps/v1
kind: Deployment
metadata:
name: maintainerr
spec:
replicas: 1
selector:
matchLabels:
app: maintainerr
template:
metadata:
labels:
app: maintainerr
spec:
securityContext:
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
containers:
- name: maintainerr
image: ghcr.io/maintainerr/maintainerr:latest
ports:
- containerPort: 6246
env:
- name: TZ
value: Europe/Brussels
# - name: BASE_PATH # if serving from a subdirectory
# value: /maintainerr
volumeMounts:
- name: data
mountPath: /opt/data
livenessProbe:
httpGet:
path: /api/health/live
port: 6246
initialDelaySeconds: 30
periodSeconds: 30
readinessProbe:
httpGet:
path: /api/health/ready
port: 6246
initialDelaySeconds: 10
periodSeconds: 10
volumes:
- name: data
persistentVolumeClaim:
claimName: maintainerr-data
---
apiVersion: v1
kind: Service
metadata:
name: maintainerr
spec:
selector:
app: maintainerr
ports:
- port: 6246
targetPort: 6246
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: maintainerr-data
spec:
accessModes: [ReadWriteOnce]
resources:
requests:
storage: 1Gi- Build rules from properties across Plex, Jellyfin, Emby, Radarr, Sonarr, Seerr, Tautulli and Streamystats, combined with AND/OR logic.
- Use Plex, Jellyfin or Emby as your media server, and switch between them with rule migration.
- Run several media servers at once - one Maintainerr instance per server, each with its own rules, collections and data.
- Smart metadata matching - resolves every item across your media server, the *arrs and Seerr by external IDs (IMDB/TMDB/TVDB), bridges missing IDs, and sanity-checks each match by release year so the right title is acted on.
- Bring your own TVDB key for a second metadata source alongside the built-in TMDB - Maintainerr cross-checks IDs and years between providers and fills the gaps from whichever has the data.
- Collect rule-matched media into a Maintainerr collection that is held for a configurable period before action - optionally pinned to the Plex home screen as a "Leaving soon" shelf.
- Run automatic collections, or manual ones you manage; add or exclude individual items even when they match a rule.
- Manage collection membership from within your media server - Maintainerr syncs manual changes back.
- On handling: delete files from disk, unmonitor or delete in Radarr/Sonarr, change quality profile, and clear requests in Seerr.
- Render configurable overlays (text, countdown, shapes, images) onto posters and title cards on your media server(s).
- Set a custom collection poster that survives recreation.
- Send notifications via Discord, Slack, Telegram, Pushover, Gotify, ntfy, Pushbullet, LunaSea, email or webhook.
- Share rules through YAML import/export, the community rule library, and cross-server migration.
- Schedule rule and collection runs with cron and watch progress live.
- Plus storage metrics, a calendar, logs, an OpenAPI/Swagger API, health endpoints, and subfolder (
BASE_PATH) hosting. - and more...
Maintainerr builds rules from data across these apps:
Tautulli is Plex-only; Streamystats is Jellyfin-only.
Each instance serves interactive Swagger / OpenAPI docs at /api/swagger (prefixed with BASE_PATH when set). For everything else, see the documentation.
Compatibility:
- Since Maintainerr v3.0.0,
/api/media-serveris the canonical API for media-server operations. /api/collectionsand other app-specific endpoints are internal application APIs and are not a backward-compatible Plex contract.
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Maintainerr serves health probes under /api/health (prefixed with BASE_PATH when set): /live (process only), /ready (also checks the database, returns 503 if it's unreachable), and /api/health (alias of /ready). The Docker image already ships a HEALTHCHECK against /api/health/ready, and the Kubernetes example above wires the liveness and readiness probes.
See the documentation for response shapes and full details.
Want the full picture? Every feature, setting, and gotcha, documented in detail:
Missing something, or want to back an idea?
Maintainerr is community-driven, and we're always looking for more hands. You don't have to be a developer:
- Code - pick up an open issue or feature request, or bring your own idea.
- Bugs - report them, or even better, send a fix.
- Support - answer questions and help others on Discord.
Start with CONTRIBUTING.md, then dive into the issues or our Discord. New contributors are genuinely welcome.
Maintainerr is free and open source. We cover the server costs ourselves and spend countless hours keeping it stable, adding features, and fixing issues. If it saves you time, chipping in keeps it going - and is hugely appreciated.
Maintainerr is built and maintained by:
- @jorenn92 - founder & original author
- @ydkmlt84 - code owner
- @benscobie - core developer (2024-2026)
- @enoch85 - code owner & current maintainer
- @SmolSoftBoi - core contributor
The overlay system was built by @gssariev, with @MrLinford, @SmolSoftBoi and @Simon-Eklundh.
...and everyone else in the community who has contributed (auto-updated):
Made with contrib.rocks.
Maintainerr is heavily inspired by Seerr (Overseerr / Jellyseerr). Some parts of Maintainerr's code are direct copies. Big thanks to the Seerr team!





