Sync
Reads films, series, tags and root folders from every Radarr and Sonarr you connect. An empty response is never treated as a mass deletion.
Radarr, Sonarr
nothing
Routarr reads your libraries, enriches every title from the metadata sources you order, and decides which root folder it belongs in. You see the whole plan first, and it writes only when you say so.
Self-hosted. One container. Dry-run is on until you turn it off.
| Title | Via rule | Destination | Gate | Status |
|---|---|---|---|---|
| #10Japanese animation | /movies/anime | RADARR | proposedRadarr | |
| Why✓genre contains Animation · observed Animation, Sci-Fi✓language is ja · observed ja✓unless certification is G · observed R, the exclusion did not firerule #10 wins by priority · #20 and #30 were not asked | ||||
| #20Concert films | /movies/concerts | RADARR | proposedRadarr | |
| Why✗#10 genre contains Animation · observed Music, Documentary✓#20 genre contains Music · observed Music, Documentary✓#20 keyword contains concert · observed concert, live | ||||
| #10Japanese animation | /tv/anime | SONARR | confirmSonarr | |
| Why✓genre contains Animation · observed Animation, Sci-Fi✓language is ja · observed janeeds your word · /tv/anime has 38 GB free, the series weighs 41 GB | ||||
| #30Family & kids | /movies/kids | RADARR | proposedRadarr | |
| Why✗#10 language is ja · observed en✗#20 genre contains Music · observed Family, Comedy✓#30 genre contains Family · observed Family, Comedy | ||||
| no rule matched | /movies | RADARR | staysRadarr | |
| Why✗#10 genre contains Animation · observed Drama, Music✗#20 keyword contains concert · observed none✗#30 genre contains Family · observed Drama, Music | ||||
| #20Concert films | /movies/concerts | RADARR | in placeRadarr | |
| Why✓#20 genre contains Music · observed Music, Documentaryalready in /movies/concerts · nothing to move | ||||
First matching rule wins. Exclusions can veto. Everything is explained.
In active development. The rule engine and the safety rails are stable, and the interface will keep moving.
Routarr is that missing decision layer: one place where the logic lives, using the folders your Arrs already have. On a webhook it decides before the download even lands, while the folder is still empty and nothing has to move.
What the payload already carriesWhere it lands
read by no ruleone folder, five films
Read by RoutarrWhere it lands
Nothing is written until an explicit action asks for it, and the global dry-run switch blocks writes at the server no matter what the interface does.
The stepReadsWrites
Reads films, series, tags and root folders from every Radarr and Sonarr you connect. An empty response is never treated as a mass deletion.
Radarr, Sonarr
nothing
Genres, language and certification come free with the sync. Add TMDb for keywords and country: one call per title, cached, deduplicated, bounded concurrency.
TMDb, AniList, OMDb…
its own cache
Rules run by ascending priority, and the first match wins. Exclusions veto a rule that otherwise matched. Anything unmatched falls to your default category.
your rules
a plan you can read
Moves are grouped per instance and target folder, written through the Arr API, then rescanned. Every applied move can be reverted.
the plan you approved
your library
one step writes to your libraryand the global dry-run switch blocks that one at the server

Combine conditions with ALL or ANY, add explicit exclusions, order rules by priority. Genre, keyword, original language, country, certification, year, status, current folder, title, external ids and age, plus the signals only your Arr has: tags, Sonarr's series type, size on disk and season count.
routes to anime
AllAny
original_languageis one ofja
genre_containscontainsAnimation
certification_inis one ofGUTV-Y
Exclusions are why this works. "Japanese animation" would swallow
My Neighbor Totoro. The deliberate exclusion of G-rated certifications hands it
to kids instead, and the interface says so.
A classification you cannot audit is one you cannot trust. Routarr records, condition by condition, what was expected and what was observed, for the winning rule and for every rule that did not win.
Akira (1988) · every rule that looked at it
met — original_languageexpected ja
observed ja
met — genre_containsexpected Animation
observed Animation, Science Fiction
met — certification_inexpected not G, U, TV-Y
observed 15
not met — genre_containsexpected Documentary, Music
observed Animation, Science Fiction
not met — certification_inexpected G, U, TV-Y
observed 15
met — genre_containsexpected Animation
observed Animation, Science Fiction
The engine itself never writes prose: it emits keys and parameters, and the text is rendered in your language at display time. The justifications are translated in all 26 languages, not frozen in English at the moment they were computed.

Routarr moves files on disk. Every one of these is on by default, they run in this order, and the first one to object stops the rest. The first alone is enough to make the whole application read-only.
On from the first launch. While it is on, nothing is written, whatever you click and whatever automation is enabled.
A hard ceiling on how many items one apply can touch. Reclassifying a whole library is a separate, deliberate action.
A destination that did not answer the last time anyone looked. A NAS that has spun down cannot be told from a dead disk, so this one asks rather than refuses.
The plan weighed against the free space the sync already recorded, counting only the bytes that cross a filesystem.
Past a number you choose, a second explicit confirmation is required, recognised by a stable error code rather than by matching English text.
Each decision is checked again against the current rules and library. A proposal the rules no longer justify is refused, not executed.
refusesstops the applyasksraises a question under its own name, which you answer
Automatic application exists, and it is off by default. When enabled it touches only titles with no files on disk yet, the case where changing the folder is a metadata write and nothing moves. Anything already downloaded stays in the human queue.
Routarr never creates a library layout. It reads the root folders Radarr and Sonarr declare, and where you want a destination they do not list you type it here and it is marked as such. Either way you attach it to a category you named, and a declared folder takes its free space and reachability from the synced folder it sits under.
PathInstanceOriginFree spaceCategory
/moviesRadarrsynced2.4 TiBstandard
/movies/animeRadarrdeclared2.4 TiBanime
/movies/kidsRadarrdeclared2.4 TiBkids
/movies/concertsRadarrdeclared2.4 TiBconcerts
/tvSonarrsynced6.1 TiBstandard
/tv/animeSonarrsynced6.1 TiBanime
/mnt/archiveSonarrsyncedunreachableunmapped
seven destinations across two instancesthree declared here, four read from the Arrs
Free space and reachability come straight from the Arr. Two folders claiming the same category on one instance is refused rather than silently resolved, and a category no folder provides is reported before it can quietly skip your media.

One dashboard over every connected instance: what is tracked, what is enriched, what is waiting for you.

Specificationv0.1.0
any numberMulti-instance
Any number of Radarr and Sonarr servers, each with its own sync interval, folders and mappings.
a secret URL per instanceReal-time webhooks
A per-instance secret URL. New additions are synced, enriched and evaluated immediately instead of at the next poll.
outranks every ruleOverride and revert
Pin a title to a category and the engine stops arguing. An override outranks every rule, and any applied move can be undone from the history.
/metrics, same API keyPrometheus metrics
Library size, decisions per category and status, instance health, and the state of the guardrails, all behind the same API key.
one generic JSON webhookOutbound notifications
One generic JSON webhook for Discord, Gotify, ntfy or Apprise, fired on a state change and never on a loop.
AES-256-GCM at restPortable config, sealed keys
Rules, categories, mappings and overrides export as JSON and travel between installations. Arr API keys are AES-256-GCM-encrypted and never leave.
docker compose up.One image carries the backend and the interface, for amd64 and arm64: a Synology or QNAP NAS, Unraid, TrueNAS, a Raspberry Pi or a plain VPS. Save the compose file, start it, and the first run needs no configuration file.
mkdir -p data && sudo chown 1000:1000 data
The container runs as uid 1000 and drops every capability, so the volume has to belong to it.
docker compose up -d
One image, backend and interface together. Nothing else to install.
docker exec routarr cat /data/routarr.api_key
The key is generated on first start and written beside the database. The log prints it once, the file keeps it.
http://localhost:9876
Global dry-run is already on. Nothing can be written until you turn it off.
services:
routarr:
image: ghcr.io/routarr/routarr:latest
container_name: routarr
ports:
- "9876:9876"
volumes:
- ./data:/data
restart: unless-stopped
cap_drop:
- ALL
security_opt:
- no-new-privileges:trueBack up routarr.db and routarr.key together.
Without the key, the stored Arr credentials cannot be recovered.
Then: connect your Arrs, map your folders to categories, write a rule and preview it, run a dry-run, and turn the global dry-run off only when you agree with the plan.
Most of the answers below are no, which is the most useful thing this section has to say.
The worryThe answerWhat guarantees it
only if you ask twice
Global dry-run, on by default
Global dry-run is on from the first launch, the option to move files on disk is unchecked by default, and applying past a threshold needs an explicit confirmation. Without the disk-move option, Routarr only re-points the library entry and leaves the files where they are.
no
The root folder, not the name
A move changes the root folder above your title and keeps the folder name exactly as it is, so a library pointed at it by Plex or Jellyfin keeps working.
no
The Arrs are a source of their own
Radarr and Sonarr are a metadata source of their own. They already report genres, original language and certification, and Routarr reads them from the same response it syncs the library with. For keywords and origin country, AniList needs no key either. TMDb, OMDb and TheTVDB are there if you want them. Sources are an ordered list, so you decide which one wins when they disagree.
no
Two fields, through their own API
It deliberately does not try. Routarr never manages downloads, indexers or the library itself. It writes exactly two things through the Arr API, the root folder and the path, then asks for a rescan.
never
No outbound request nobody asked for
No telemetry, no analytics, no update check. The only outbound calls go to your Radarr and Sonarr instances, to the metadata sources you enable (TMDb, AniList, Jikan, OMDb, TheTVDB), to your OpenID Connect provider if you use one, and to a notification webhook if you set one.
yes
One environment variable
Including under a sub-path. Set ROUTARR_BASE_PATH=/routarr and the API, the interface and the webhook URLs all move with it, with no image rebuild.
a Pi is enough
One image, one file
One Docker image for amd64 and arm64, so a Pi or an N100 is enough. Storage is a single SQLite file. There is no database service to run.
Read the plan, keep what you agree with, and let the rules do the rest.
What you have just been shown
Global dry-run is on from the first launch, and five more gates stand after it.
What each condition expected, what it observed, and the rules that did not win.
amd64 and arm64, a single SQLite file, no database service to run.