Janitorr clears stale media from Radarr, Sonarr and Jellyfin before disk fills
Cleans your Radarr, Sonarr, Jellyseerr and Jellyfin before you run out of space
At a glance
- What is it?
- A Kotlin service that deletes media nobody watched and clears leftover requests and metadata, shipped as a Docker image with dry-run mode enabled by default. It works from grab history rather than watch history, and it needs write access to your media library.
- Who is it for?
- Janitorr fits self-hosted library operators who want an automated answer to old unwatched downloads, especially when Jellyfin or Emby already accumulate orphaned folders. It is the wrong tool if your policy is to delete only after something has been watched, because Janitorr works from grab history, and it is not a Plex option since the author points Plex users to Maintainerr.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 20 days ago.
- What is it written in?
- Mainly Kotlin, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A janitor for the media server, not a media manager
The description puts the intent plainly: Janitorr cleans Radarr, Sonarr, Jellyseerr and Jellyfin before you run out of space. The problems it names are recognisable for anyone running a shared server. Media accumulates that is never watched. Users request episodes through a request service and then leave them sitting on disk. The library fills up, and the person who notices is the one administering it. Janitorr takes that chore over by applying configured expiration times to media in the arrs, removing old seasons or entire shows, clearing finished requests and removing the leftover metadata in Jellyfin so that no orphaned files remain. It is written in Kotlin and is aimed at operators of self-hosted libraries rather than at content discovery, since the source of the decision is what already sits in your download clients.
Dry-run mode is on in the template, so nothing is deleted by accident
The safety story is built into the default configuration. Dry-run mode is enabled in the config template, and unless you disable it nothing is deleted. The README asks you to watch the logs to see which actions Janitorr intends to take, which turns a destructive tool into a two-step decision: read the log, then switch on deletion. A second safety path exists for people who are still not convinced. Enable the Recycle Bin inside the arrs and disable Jellyfin and Emby, and the deletes triggered in the arrs land in the Recycle Bin while nothing at all is triggered on Jellyfin and Emby. The author also asks that you use the tool at your own risk, which is a fair description of a component that deletes the files your users depend on. The recommendation to create a dedicated user for the library side makes the same point about credentials.
Age comes from grab history, not from watch history
The mechanism that decides when something expires is worth understanding before you configure anything. Age is determined from your grab history in the arr apps, and by default the oldest file in that history is chosen. If Jellystat or Streamystats is configured, the most recent watch date overwrites the grab history when one exists. That is the pivot of the whole design. Janitorr asks how long ago this content was acquired and how long ago it was watched, and it will happily delete something that was downloaded two years ago even if it was watched yesterday, unless the watch date is available and applied. The project states plainly that Janitorr does not delete items after they have been watched, and points readers to the Jellyfin Media Cleaner plugin for that behaviour instead.
janitorr-stats keeps watch history alive when Jellyfin item IDs change
The optional companion service janitorr-stats exists because Jellyfin's internal item IDs are not stable. It stores play history keyed by stable external IDs such as IMDB, TMDB and TVDB, so the history survives library rescans, file moves and server migrations that change those internal IDs. The caveats are stated as plainly as the feature. It only records what is watched while it is running, so it does not backfill historical activity and knows nothing on day one, which means its usefulness grows with uptime. When both Jellystat or Streamystats and janitorr-stats are enabled, Janitorr queries the primary source first and only falls back to janitorr-stats when the primary returns no result. If you are starting fresh with no stats app running, the README's advice is to enable janitorr-stats from the start and skip the others. Pointing Janitorr at it is a short configuration block:
Wiring Janitorr to the janitorr-stats container
The connection is made in the application configuration, where the companion service is enabled and given its URL:
clients:
janitorr-stats:
enabled: true
url: "http://janitorr-stats:8080"The container setup for the companion itself is documented in the janitorr-stats README. Beyond that block, the configuration file also carries the API keys for the arr apps, Jellyfin or Emby and Seerr, the expiration settings, and the tag used for exclusions. Exclusions work through a tag applied in Sonarr or Radarr, and the actual tag name Janitorr looks for can be changed in the configuration file. For weekly shows you can keep a minimum number of episodes instead of removing a whole season, and shows can be removed entirely. The Leaving Soon collections are a deliberate exception to the dry-run rule: they are always created, and they show rule-matched media on the Jellyfin home screen for a set duration before deletion, which gives viewers a warning window.
Reading the logs is how you verify what the tool intends to do
Janitorr writes to stdout, so the container logs show what the application wants to do, but file logging is recommended instead so the history survives a container replacement. If you turn file logging on, the chosen location has to be mapped into the container, otherwise the log files end up inside the container instead of on the host. For troubleshooting, the log level is raised by editing one line in the application configuration, where the package logging level is set to INFO by default:
com.github.schaka: INFOChanging INFO to DEBUG or TRACE gives more detail about which rules matched and which actions were planned. The project also keeps a wiki with a troubleshooting section and common errors, plus an FAQ page and discussion board, and asks that existing issues are checked before a new one is opened.
The constraints that decide whether it fits your setup
Several limits are documented, and they narrow where Janitorr works. Jellyfin and Emby require a user with access to delete files, since an API key alone is not sufficient, which is why the author suggests creating a dedicated user for the task. Only one of Jellyfin or Emby can be enabled at a time, and only one of Jellystat or Streamystats. For media to be picked up at all, it has to have been downloaded by Radarr or Sonarr. Jellyfin and Emby are not required, but without them you can end up with orphaned folders and metadata. Emby support is implemented and tested, yet the author states plainly that Emby is not used personally and that maintenance relies on bug reports, which is a fair signal about where the confidence sits. The code is published only as a Docker image to GitHub Packages, so anyone without Docker has to compile the project from the source tree.
Maintainerr for Plex, Media Cleaner for watch-based deletion
Two alternatives are named in the README, and each differs in what it uses as the trigger. Maintainerr is the reference point for Plex users: Janitorr is described as heavily inspired by it but not a fork, and users inside the Plex ecosystem who want an easy GUI and more sophisticated functionality are told they are better off with Maintainerr instead. The second is the Jellyfin Media Cleaner plugin, which answers the question Janitorr deliberately leaves open. Janitorr works from grab history and will not delete an item just because it was watched, whereas Media Cleaner is the tool for deletion based on watched status. Maintenance is active enough to judge from the record: releases v2.2.2, v2.2.1 and v2.2.0 landed on 2026-09-19, 2026-09-11 and 2026-08-22, the last push was on 2026-10-03, and the licence is GPL 3.0, which is worth reading before you embed it in a hosted setup of your own.
Editorial conclusion
Janitorr fits self-hosted library operators who want an automated answer to old unwatched downloads, especially when Jellyfin or Emby already accumulate orphaned folders. It is the wrong tool if your policy is to delete only after something has been watched, because Janitorr works from grab history, and it is not a Plex option since the author points Plex users to Maintainerr. Before deploying it, run with dry-run mode enabled, confirm the application.yml API keys, and check that the media library account holds delete permission.
Frequently asked questions
Does Janitorr delete media when it starts?
No. Dry-run mode is enabled in the config template by default, and unless you disable it nothing is deleted. The container logs show which actions the application intends to take.
Can I run Janitorr without Docker?
Not from a published image. The code is published only as a Docker image to GitHub Packages, so without Docker you have to compile it yourself from the source tree.
How does Janitorr decide that media is old?
Age is determined from your grab history in the arr apps, and by default the oldest file in that history is chosen. If Jellystat or Streamystats is set up, the most recent watch date overwrites the grab history when one exists.
Does Janitorr delete an item after it has been watched?
No, that is explicitly not what it does. The README points to the Jellyfin Media Cleaner plugin for deleting items once they have been watched.
What permissions does Janitorr need on Jellyfin or Emby?
User access to delete files, since an API key alone is not enough. The author recommends creating a dedicated user for this task, and only one of Jellyfin or Emby can be enabled at a time.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/schaka-janitorr)Was this useful?