semantic-release-bot ddd0802b3a chore(release): 3.26.0
2026-08-30 13:48:50 +00:00
2026-08-30 13:48:50 +00:00
2026-03-30 17:59:25 +00:00
2026-08-30 13:48:50 +00:00
2026-08-30 13:48:50 +00:00

Maintainerr's custom image

Founded in 2021 - real human work, before mainstream AI.

Discord GitHub Actions Workflow Status GitHub Release GitHub commits since latest release GitHub Repo stars Docker Pulls GitHub commit activity GitHub Issues or Pull Requests GitHub Issues or Pull Requests Static Badge Documentation GitHub License

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!

Installation

Docker images for amd64 & arm64 are available from:

GHCR

Docker Hub

Data directory. Maintainerr stores its data at /opt/data inside the container. Mount a persistent volume there in your docker run command or Compose file. The directory must be readable and writable by the configured user; if no user is set, make it accessible to UID:GID 1000:1000.

CPU requirement (x86-64). Image features (overlays and collection posters) use sharp, whose prebuilt binaries require a CPU with the x86-64-v2 microarchitecture. Maintainerr still starts on older CPUs, but those features are disabled. If you run in a VM and hit this, set the VM CPU type to host, x86-64-v2, or newer (e.g. Proxmox/QEMU's default kvm64 does not expose x86-64-v2). This does not apply to arm64.

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:latest
Docker 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
#          - type: bind # uncomment for the leftover-folder cleanup: your library, at the same path Radarr/Sonarr report it at
#            source: /path/to/media
#            target: /path/to/media
        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)
#          - TELEMETRY=off # uncomment to switch off the anonymous weekly usage report
#          - SPORTARR_NET=on # uncomment to read Sportarr league artwork from sportarr.net
        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: 3
Kubernetes (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

Features

  • Build rules from properties across Plex, Jellyfin, Emby, Radarr, Sonarr, Sportarr, Seerr, Tautulli, Streamystats, and Tracearr, combined with AND/OR logic.
  • Use Plex, Jellyfin or Emby as your media server.
  • Switch between media server types with rule migration.
  • Deploy separate Maintainerr instances for separate media servers, each with isolated 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.
  • Keep a collection inside Maintainerr, with no collection created on your media server - the rule, its actions, overlays and *arr tags all still run. Per collection, off by default.
  • Delete items from your download client.
  • 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/Sportarr, 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, including when a newer Maintainerr version is available.
  • 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:

Plex Jellyfin Emby Seerr Radarr Sonarr Sportarr Tautulli Streamystats Tracearr

Tautulli is Plex-only; Streamystats is Jellyfin-only; Tracearr supports Plex, Jellyfin, and Emby; Sportarr manages sports libraries.

API

Each instance serves interactive Swagger / OpenAPI docs at /api/swagger (prefixed with BASE_PATH when set). For everything else, see the API documentation.

Compatibility:

  • Since Maintainerr v3.0.0, /api/media-server is the canonical API for media-server operations.
  • /api/collections and other app-specific endpoints are internal application APIs and are not a backward-compatible Plex contract.

Preview

Collections Rules
Rule configuration Overlays
Calendar Storage metrics

Health endpoints

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.

Help us help you

Maintainerr reports anonymous usage once a week. It is the only signal we have about which versions, media servers and features are actually in use, and it decides what gets built, fixed and kept.

Nothing identifies your server: no account, no instance id, no hostname, no URL, no API key, no library or media name, and no IP address is read or stored. A report carries the version and platform every week, and one week in 32 a bucketed picture of which features and rule properties are in use.

We checked, and reporting by default is normal for tools like ours. Where we differ is in what a report is allowed to contain.

How it works Common practice Maintainerr
Goes to a third party Yes, Google Analytics or Sentry No, our own collector
Identifies your install Yes, a permanent id per install No, no id at all
Sees your IP address Yes, the receiving service does No, never read or stored
How often Every action Once a week

The exact shape of a report is one TypeScript interface, TelemetryPing. What happens to it after it arrives is documented in the collector repository, and the dashboard shows what it adds up to.

Documentation

Want the full picture? Every feature, setting, and gotcha, documented in detail:

Documentation

Feature requests

Missing something, or want to back an idea?

Vote on features

Contributing

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.
  • Translations - see below. No git or coding needed.
  • 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.

Translations

Translation status

Maintainerr uses Weblate for translations. Pick your language, edit in the browser, and your work reaches everyone in the next release - no git, no pull request, no build tooling.

Missing a language? Request it on Weblate and start it yourself.

Support us

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.

Donate

Credits

Maintainerr is built and maintained by:

The overlay system was built by @gssariev, with @MrLinford, @SmolSoftBoi and @Simon-Eklundh.

...and everyone else in the community who has contributed (auto-updated):

Maintainerr contributors

Made with contrib.rocks.

Maintainerr is heavily inspired by Seerr. Some parts of Maintainerr's code are direct copies. Big thanks to the Seerr team!

S
Description
No description provided
Readme MIT 111 MiB
Languages
TypeScript 94.4%
JavaScript 4.9%
CSS 0.4%