Post 10 built the plumbing. This page is about the brains: Sonarr and Radarr, and the three decisions inside them that determine whether your library is a library or a junk drawer. I’ve run these tools for a long time; what follows is the settled residue of getting each piece wrong at least once.
The mental model
A *arr is a reconciliation loop. You declare what you want (this show, this quality range), it continuously compares that against what you have, and it closes the gap: searches the indexers, hands the pick to a download client, waits, then renames and moves the result into the library. That last step is where most setups quietly rot. The *arr is the single naming authority for your library; everything in this post flows from taking that seriously.
Prowlarr sits beside them as the indexer hub: sources get configured once there and sync to every *arr. Add an indexer in one place, it appears everywhere. The alternative, maintaining indexer lists per app, is a five-minute job that multiplies into an evening.
Step 1: naming templates, set once, never touched
These pair with the Plex scanner expectations from post 15 (year, provider ID, SxxEyy). Sonarr, Settings, Media Management:
Series folder:
{Series TitleYear} {tvdb-{TvdbId}}
Season folder:
Season {season:00}
Episode (standard):
{Series TitleYear} - S{season:00}E{episode:00} - {Episode CleanTitle} [{Custom Formats }{Quality Full}]
Radarr, same idea:
Movie folder:
{Movie TitleThe} ({Release Year}) {imdb-{ImdbId}}
Movie file:
{Movie TitleThe} ({Release Year}) {imdb-{ImdbId}} [{Custom Formats }{Quality Full}]
What each piece does: the year disambiguates remakes; the
{imdb-}/{tvdb-} token makes Plex’s matching deterministic (the
scanner reads the ID and stops guessing); CleanTitle strips
characters that upset some filesystems and at least one TV client;
the quality block in brackets is for humans, handy for seeing at a
glance what an upgrade replaced.
Turn on Rename Episodes, and under Importing leave “Use Hardlinks
instead of Copy” enabled. That setting only delivers if you built the
/data single-mount convention from post 15. If your imports are
slow copies, fix the mounts, not this checkbox.
Step 2: quality profiles that terminate
The classic failure: enable every quality from DVD to remux, allow upgrades across the whole range, and spend the year re-downloading the same titles in ever-fatter files. A profile should answer two questions: what’s acceptable now, and where does upgrading STOP.
Mine, after plenty of oscillation:
- TV (WEB-1080p). WEBDL-1080p and WEBRip-1080p acceptable, upgrade-until WEBDL-1080p. TV gets watched once on TVs and phones; 1080p WEB is the sweet spot of quality, size, and availability.
- Movies (HD-1080p). Bluray-1080p preferred, WEBDL-1080p acceptable, upgrade-until Bluray-1080p. No remuxes: a 60GB file whose extra bits my screens can’t show is just a slower backup.
- 4K: a deliberate non-goal until every link in the chain (displays, storage, transcode math) says yes. Half-committing to 4K gets you a library that’s 10% huge files you transcode down anyway.
The principle: upgrades must terminate. Every profile gets an explicit upgrade-until ceiling. Once a title reaches it, the loop goes quiet. A profile without a ceiling is an agreement to churn bandwidth forever.
Step 3: custom formats, using other people’s homework
Quality alone can’t express “prefer proper releases, avoid x265 re-encodes of WEB sources, never touch these groups.” Custom formats can: they’re matchers that add or subtract score from candidate releases, and the *arr picks the highest score within the allowed qualities.
They’re also a rabbit hole. The TRaSH guides (trash-guides.info) maintain battle-tested format definitions and scoring for exactly the profiles above: unwanted-release filters, repack handling, codec steering, group lists. Use theirs. Hand-rolling custom formats is for the day their sets don’t cover your problem, and that day took years to arrive for me.
Step 4: recyclarr, so the settings live in git
Everything above is configured through web UIs, which means none of it is in the repo, none survives a rebuild, and none has a diff history. recyclarr fixes that: a small container that reads YAML and pushes TRaSH quality definitions, custom formats, scores, and naming config into Sonarr and Radarr on a schedule.
# config/recyclarr/recyclarr.yml (excerpt)
sonarr:
main:
base_url: http://sonarr:8989
api_key: !env_var SONARR_API_KEY
quality_definition:
type: series
custom_formats:
- trash_ids:
# repack/proper handling, unwanted filters, ...
assign_scores_to:
- quality_profile:
name: WEB-1080p
The YAML lives in the repo, the API keys ride the sops pipeline (post 4), the sync runs nightly. Now the *arr config has the same properties as everything else in the lab: versioned, reviewable, rebuildable. When a TRaSH update changes scoring, it shows up as a diff in recyclarr’s logs instead of as mystery behavior.
The caveat: recyclarr owns what it manages. Hand-edit a custom format it controls and the next sync reverts you. That’s the two-authorities problem from post 15 in a different hat. Decide per-knob whose it is, and don’t share custody.
The end-to-end trace
One request, no humans:
1. someone adds a show in the request portal
2. portal -> Sonarr: monitored series, WEB-1080p profile
3. Sonarr -> Prowlarr-synced indexers: search
4. candidates scored by profile + custom formats
5. winner -> qBittorrent (inside gluetun, post 10)
6. download lands in /data/torrents/...
7. Sonarr imports: HARDLINK to /data/media/tv/Show (Year) {tvdb-...}/
Season 01/Show - S01E01 - Title [WEBDL-1080p].mkv
8. webhook -> autoscan -> Plex scans one directory
9. it's on the TV before the requester's kettle boils
Steps 4 and 7 are this page, and they’re the two you can’t patch by hand later without making everything worse. Good news, everyone: you only have to set them up once.
Next, back on the main line: knowing when any of this breaks before the household does.