Sonarr
Sonarr is the brain of the TV side of the stack. You tell it which series you care about; it watches for episodes, asks the indexers, hands the best result to a download client, and then renames and files everything so your media server can make sense of it.
This guide assumes The Media Stack is running and Prowlarr has synced its indexers.
Sonarr is a PVR for Usenet and BitTorrent. Version 4 is current.
- Monitors series and seasons, grabs new episodes as they air
- Quality profiles — define what "good enough" means, and it upgrades automatically when something better appears
- Renames and organises into a consistent structure Plex and Jellyfin can parse
- Handles the messy parts of TV: multi-episode files, season packs, absolute numbering for anime, specials
- Failed download handling — a release that does not import gets blocklisted and replaced automatically
- Calendar and iCal feed so you know what is coming
1. The container
sonarr:
image: lscr.io/linuxserver/sonarr:latest
container_name: sonarr
restart: unless-stopped
environment:
- PUID=99
- PGID=100
- UMASK=022
- TZ=Europe/London
volumes:
- /mnt/user/appdata/sonarr:/config
- /mnt/user/data:/data
ports:
- 8989:8989
The single /data mount is what makes hardlinks and instant imports work. If you skipped that section, go back — this is the decision that costs you a weekend later.
2. Authentication
http://<host-ip>:8989. Set Forms (Login Page) with a username and password.
Grab your API key now from Settings → General — Prowlarr, Bazarr and Seerr will all want it.
3. Set the update mechanism
Settings → General → Updates → Mechanism: Docker.
Do this before you forget. Sonarr's built-in updater does not work sensibly in a container — it either fails, or succeeds and gets wiped by your next docker compose pull.
4. Add the root folder
Settings → Media Management → Root Folders → Add Root Folder
Set it to /data/media/tv.
The root folder must be inside /data
Not /tv. Not /mnt/user/data/media/tv. The path as the container sees it, which with the standard mount is /data/media/tv. Get this wrong and imports either fail or copy instead of hardlink.
5. Media Management settings
Same page, and these are the ones that matter:
| Setting | Value | Why |
|---|---|---|
| Rename Episodes | On | Otherwise you keep the release group's naming |
| Replace Illegal Characters | On | Windows shares will thank you |
| Use Hardlinks instead of Copy | On | The whole point |
| Import Extra Files | On, srt,sub |
Picks up bundled subtitles |
| Unmonitor Deleted Episodes | On | Stops it re-downloading things you deleted on purpose |
Turn on Show Advanced Settings (the toggle at the top) to see the hardlink option.
For naming, the TRaSH Guides recommended format is worth pasting in rather than inventing your own. Both Plex and Jellyfin parse it correctly, which is not true of every scheme.
6. Connect the download clients
Settings → Download Clients → +
qBittorrent:
| Field | Value |
|---|---|
| Host | qbittorrent |
| Port | 8080 |
| Username / Password | Your WebUI login |
| Category | tv |
SABnzbd:
| Field | Value |
|---|---|
| Host | sabnzbd |
| Port | 8080 |
| API Key | From SABnzbd |
| Category | tv |
The category is what routes downloads into /data/torrents/tv and /data/usenet/complete/tv. It must match the category you configured in the client itself. Mismatched categories are the single most common cause of "downloaded but never imported".
Under Settings → Download Clients → Completed Download Handling, leave Remove on for Usenet, and off for torrents if you care about seeding ratios.
7. Check the indexers arrived
Settings → Indexers should already be populated by Prowlarr, each name suffixed (Prowlarr).
Empty? Go back to Prowlarr, Settings → Apps, and hit Sync App Indexers. Do not add indexers here manually — Full Sync will remove them.
8. Quality profiles
Settings → Profiles. The defaults work, but two adjustments make a real difference:
Set a sensible cutoff. A profile with HDTV-720p through Bluray-2160p all enabled and no cutoff will keep upgrading forever, re-downloading the same episode at increasing sizes. Set the cutoff to where you actually stop caring — usually WEBDL-1080p.
Add a size limit. Settings → Quality lets you set min and max MB per minute per quality. Capping WEBDL-1080p at around 100 MB/min keeps 40 GB "1080p" remuxes out of your library.
If you want to go further, TRaSH's custom formats let you prefer specific release groups and reject bad encodes. That is a rabbit hole; the defaults are fine to start.
9. Add a series
Series → Add New, search, pick it.
| Field | Note |
|---|---|
| Root Folder | /data/media/tv |
| Monitor | All for a finished show, Future Episodes for one still airing |
| Quality Profile | Whichever you configured |
| Series Type | Standard, or Anime if it uses absolute numbering |
| Season Folder | On |
Tick Start search for missing episodes and it goes to work immediately.
Watch Activity → Queue to see the grab, then Activity → History for the import. A successful import shows the file moving from /data/torrents/tv/... to /data/media/tv/....
10. Verify the hardlink
The first import is the one to check:
Link count of 2 in the second column means hardlinked. 1 means Sonarr copied it, your disk usage just doubled, and something is wrong with your mounts.
Updating
Sonarr migrates its database on start. Watch the logs the first time after a major version change:
Backup
/mnt/user/appdata/sonarr holds sonarr.db — your entire series list, history and settings.
Turn on System → Backup → Scheduled in the UI, then include the appdata folder in your host-level backup:
docker compose stop sonarr
sudo tar czf /mnt/user/backups/sonarr-$(date +%F).tar.gz -C /mnt/user/appdata sonarr
docker compose start sonarr
Stop it first. A SQLite database copied mid-write restores as a corrupt database, and you will not find out until you need it.
Troubleshooting
Download completes but never imports. In order of likelihood: category mismatch between Sonarr and the client; the download client reporting a path Sonarr cannot see; permissions. Check Activity → Queue — Sonarr usually states the reason on hover.
"Permission denied" on import. PUID/PGID. ls -la the downloaded file and compare against Sonarr's env vars. chown -R 99:100 /mnt/user/data.
Imports are copies, not hardlinks. Multiple volume mounts, or downloads and media on different Unraid shares. See the layout section.
Nothing is found for a show that definitely has releases. Check Manual Search on a specific episode — it lists every release and, crucially, the reason each was rejected. Usually a quality profile that excludes everything available, or a size limit that is too tight.
Anime episode numbers are wrong. Set Series Type to Anime. Sonarr then uses absolute numbering and consults AniDB mappings.
Same episode downloading over and over. No cutoff on the quality profile, so every slightly-better release triggers an upgrade. Set one.
Series added but the calendar is empty. TheTVDB has not got the schedule, or the series is unmonitored. Series → Edit → Monitor to check.
Sonarr is very slow on Unraid. appdata on the array rather than the cache pool. Move it.
Where this sits in my lab
Sonarr runs on the Unraid box with the rest of the stack, pulling from both Usenet and torrents through Prowlarr, and handing off to SABnzbd or qBittorrent depending on where the release came from.
Requests arrive from Seerr, so the people who watch the TV never see this interface — which is the correct arrangement, because the quality profile screen is not a thing anyone else should have opinions about.