storage categories and rules - degoya/rDownloader GitHub Wiki
Where a download lands is decided by three things, in this order: a routing rule picks a category, the category names a path inside a storage root, and the package gets its own directory below that.
<storage root>/<category path>/<package name>/<file>
All of it lives under Settings → Storage & rules, which has three tabs: Storage roots, Categories and Rules. Watched folders and the LinkGrabber have settings pages of their own.

A storage root is an allowlisted base directory. You can have several — one on a fast disk, one on a big one, one on a network share.
A storage root stays away from rDownloader's own folders. It may not be, contain or lie inside
the data folder, the scripts folder, the vendor or managed-tool folders or the plugin folder, so a
download can never become a program the service runs. Such a root is refused with
storage_root.protected_directory, naming the folder it collides with. Point the root at a folder
of its own — in the container, /downloads or /media/movies, never a folder under /config.
Exactly one root is always the default, and the same holds for categories:
- the first root created is the default, whatever the form said;
- the last default cannot be given up;
- deleting the default hands the flag to another root;
- restoring a backup repairs a bundle that claims none or several.
Each root has a minimum free space threshold, with a global default. The global default, the headroom for files of unknown size, the global collision policy and automatic resume are the Storage capacity card below the roots on the same tab; a root's own threshold overrides the global one for that root.
- A root below its threshold is blocked on its own: its downloads stay queued and its intake is
refused with
storage.capacity_blocked— queueing a reviewed NZB included, from the interface, the API, MCP or the SABnzbd adapter — while every other destination keeps running. - The block survives a restart, so with automatic resume off nothing resumes silently.
- Release it by hand from the interface, or with
POST /api/v1/storage/capacity/{target}/resume, which requeues exactly the downloads it held back. - A transfer whose size no runner can state may start while a configurable multiple of the threshold is free.
The same check applies to every kind of transfer before it starts — HTTP, Usenet, torrents, media, galleries, streams, FTP/SFTP, buckets and plugin transfers alike — and a download it stops is Blocked with the same reason whatever its kind, so releasing the root brings every one of them back. A package's folder is usually created only when its download starts; until it exists, the check measures the free space of the nearest folder above it that does exist, which is the disk the folder will be created on. A filesystem that cannot preallocate a file is not an error; actually running out of space is.
Released only when a download can start. With Resume automatically on, a blocked root is released once at least one download waiting on it — held back by the block, queued, or waiting for a retry — would pass the start check: the threshold plus that download's remaining size must be free, or, for a download of unknown size, the threshold times the headroom. Free space just above the threshold is not enough while every waiting download needs more, so the root stays blocked instead of being released and blocked again every few seconds, and no notification or automation fires for a release that would start nothing. A root nothing waits on is released as soon as its free space is back at the threshold.
A destination that cannot be used says which part is wrong, with the path attached: the path is a file, no permission, a read-only filesystem, not creatable, not writable, not absolute. The check writes a probe file and removes it again.
A storage root whose path will not survive the container is badged in the routing view, flagged in
the readiness card and reported by the MCP configuration tool. A path outside a mounted volume is
created inside the container's writable layer, so downloads run normally and everything is gone on
the next docker rm.
Only a container's overlay root filesystem counts, so a bare-metal install on btrfs or zfs is never
flagged. tmpfs and ramfs count anywhere.

A category has a name, a colour and a relative destination structure inside a storage
root. The colour comes from the picker or is typed as an exact #rrggbb. A category whose storage
root is gone, or whose folder would lead out of it, refuses new work with
category.destination_unresolved until it is fixed. Packages get their own subdirectory within it.
With categories on more than one storage root, the list is grouped by root in sections that fold open and shut.
Duplicate on a category makes a copy with every setting under a free name and opens it in the form. The default mark stays with the original, and so do the rules that point at it.
Show in the selection, on by default, decides whether you can pick the category by hand. Switched off, the category no longer appears in the pickers that assign a category: the LinkGrabber's package and NZB rows, its file import and selection bar, and the Downloads' package rows, add dialog and selection bar. Rules, subscriptions, watched folders, the compatibility interfaces, the REST API, the MCP server and the list filters keep using it, and a package that already has it still shows it as its value. The default category is always offered: it cannot be switched off, and a category that becomes the default is switched back on.
A category can also carry defaults that override the global ones:
- post-processing level,
- user script,
- cleanup extension list,
- SFV verification,
- "post-process only verified packages",
- PAR2 deletion,
- recursive unpacking,
- Subfolder per archive — Inherit, On or Off: unpack each archive into a folder of its own,
- Dissolve a folder named like the package — Inherit, On or Off: move the content of a single folder carrying the package's name up one level (see Post-processing),
- Unpack while downloading — Inherit, On or Off: unpack a Usenet package's multi-part RAR archive while it downloads (see Post-processing),
- rclone upload target,
- Sort series and films — templates that file finished episodes and films below the category's folder (see Post-processing),
- Tidy package names — Inherit, On or Off per rule: how the name, and so the folder, of a new package in this category is tidied; the editor shows what Big Buck Bunny [1080p] becomes (see Post-processing). This is the package folder's name — the Tidy file names step tidies the files inside it,
- Own regex rules — a list of find → replace rules of its own that replaces the global list (see Post-processing),
-
Download window — weekly time spans in which the category's packages may download, and
the exception Ignore the schedule's pause; a package's own window wins (see
Download windows; REST
PUT /api/v1/categories/{id}/download-window, MCPset_category_download_window), - On a name collision — see Name collisions and duplicates.
See Post-processing for what each of those does.

Changing a package's category moves its data into the new
<category-path>/<package-name>/ and clears the directory it came from.
- Files still transferring keep their partial file and are promoted into the new folder when they finish, so the move never interrupts a running download.
- While a package is being post-processed or unpacked, the move waits and runs once that has ended.
- A directory is only removed while it is empty.
- A destination on another disk gets a verified move: the original is removed only after the copy's SHA-256 matches. A move stopped by a crash is finished at the next start.
- Every move is kept in the storage history — see Moves, links and reuse.

Rules assign a category automatically. They are prioritised and first-match: the first rule that matches wins, and the rest are not consulted.
The precedence is the same for every intake, links and files alike:
- A category somebody chose for this intake — the watched folder's setting, the upload
form's field, a SABnzbd client's
cat. - The first matching rule.
- The category marked as default.
The first entry of every category picker is called Automatic. It is not a category: it means nothing is pinned and the rules decide. The same file dropped a second time is routed again rather than keeping what the first drop decided; an import that has already become a package is left alone.
Criteria:
| Criterion | Example |
|---|---|
| Intake source | LinkGrabber, hotfolder, extension context menu, intercepted browser download, subscription |
| Domain | example.com |
| Protocol |
http, ftp, nzb, torrent, … |
| File extension | .mkv |
| MIME type | video/* |
| Name regex | /^S0\d/ |
Intercepted browser downloads count as their own intake source, so they can be routed separately from links you sent through the extension's context menu.
Match the name against decides which name the name regex is tried on:
- File name (the default, and what every rule written before 1.14 keeps) — the link's file name.
- Package name — the name of the LinkGrabber package the link is grouped into; for an NZB, its own name.
- Either — one of the two matching is enough.
The package name helps when the hoster files carry obfuscated names: a release such as
Game.Update.v1.2.0.NSW-GROUP whose parts are called a8f3c91d0e.part1.rar still reaches an
Updates category with the pattern (?i)update.*nsw- and Package name selected. The rules are
evaluated once, when the links arrive: renaming the package in the LinkGrabber later, or a regroup
after the online check, does not route it again, and a category you chose yourself is never
replaced.
A visual regex editor helps build the name pattern; its tester follows the name the rule matches. The same editor is available on subscription title filters.
Under the pattern the editor draws it as a diagram, so you can read what it does before you save it: boxes in a row for Starts with, text, Any digit and the other placeholders, a group as a labelled frame (Group #1, or its name), alternatives and character classes as a One of stack, and ↻ 1–∞ under anything that repeats. The diagram comes from rDownloader itself, from the same regex engine the rules run with, and follows your typing. An invalid pattern shows its error instead; a very large pattern says it is too large to draw. A wide diagram scrolls sideways inside the editor, and a screen reader reads it as a list of steps (Starts with, then Text "http", then Text "s" (optional), …).
Two different questions, answered apart: is this file name already taken at the destination? and do I already have this?
A finished file that meets a name already taken at its destination follows one visible policy, On a name collision:
| Policy | What happens |
|---|---|
| Rename | The new file lands beside the existing one as name (1); nothing is lost. |
| Skip | The new file is not written; the existing one stays and the download ends with a note. |
| Overwrite | The new file replaces the existing one. Recorded in the audit log, and never done over a file that is being transferred or seeded. |
| Compare | The contents are compared: identical bytes adopt the existing file, different ones are renamed. |
| Ask | The download waits until somebody decides. Only this download waits, and the question survives a restart. |
The policy is set at three levels, the most specific one winning: per package (in its Collisions and duplicates dialog), per category (in the category form, or Inherit the global setting), and globally in the Storage capacity card under Settings → Storage & rules → Storage roots. The package dialog shows which one is in effect and at which level.
With Ask, the downloads view shows a prompt — "name" already exists — saying whether the name was taken before anything was downloaded or while the transfer ran (the verified file then waits in the staging folder), and offers Rename, Skip or Overwrite. The rest of the queue keeps running. The same question can be answered over the REST API or MCP.
A package's menu opens Collisions and duplicates, which lists two kinds of duplicate separately:
- Same source — the same thing was asked for before, recognised before a byte is fetched: by the normalised address, a magnet's info-hash, an NZB's hash and file name, or hoster and address. It says whether the other copy is in the queue or in the LinkGrabber, and the LinkGrabber marks such links too.
- Same content — the same bytes are already on disk, recognised by the SHA-256 of the finished file (for an unfinished file, the SHA-256 its source stated, if any). The index of finished files follows moves and removals and marks a file that went missing.
Replace with a link turns an identical file into a hard link to the other one, so the bytes are stored once. Both files are hashed first, and it works only on the same file system; on another one the dialog says no link is possible. Nothing is linked unless you ask for it.
The Storage roots tab ends with Moves, links and reuse:
- Hard links per storage root — whether each root supports hard links, found out by trying. Reflinks are not created.
- Reuse per kind of transfer — what each kind of transfer (HTTP, Usenet, media, gallery, recording, torrent, FTP, SFTP, plugin transfers) does with data already on disk: resume, re-check partial data, adopt finished files, verify, and whether the collision policy applies to it.
- History — every move and every duplicate link, newest first, with its state and whether it was verified. Check the content index compares the index with the disk and reports how many entries it checked, found missing, found again and added.
Two buttons empty what this card keeps. Each asks first and names the count:
- Clear history removes the completed, failed and interrupted moves and duplicate links from the history for good. An operation still running stays. No file is moved or deleted, and an interrupted move is still carried on at the next start.
- Clear index, beside Check the content index, empties the content index — the list of finished files with their SHA-256 that tells rDownloader two files are identical. Files and downloads stay untouched, but until a file is indexed again it is not recognised as a content duplicate and cannot be the original of a duplicate link: Replace with a link is refused for it. Check the content index — which also runs at every start — indexes again every finished download still in the queue whose SHA-256 is known and whose file is still in place. The files of downloads you removed from the queue, or that were never hashed, come back only when they are downloaded again.
Both are recorded in the audit log with the number of entries removed. Over the
REST API and the MCP server they need the
api:admin permission area; checking the index needs only api:queue.
Export under Settings → Storage & rules writes the routing configuration to a file and asks what goes in: Everything (categories and rules), Categories only or Rules only. Import reads such a file on this or another installation and says how many categories and rules it holds before anything changes.
- Entries are merged by name: an existing category or rule with the same name is kept, only new ones are added.
- Rules refer to their category by name. A rules-only file therefore needs the categories to exist on the target already; a rule whose category is missing is skipped and counted in the summary.
The same export is available as GET /api/v1/routing/export?part=all|categories|rules; without
part it exports everything.
Storage roots and categories that are still referenced cannot be deleted.
The options for link intake have a page of their own, Settings → LinkGrabber, with the tabs General, Blocklist, Containers and LinkFilter — the blocklist of excluded domains, the DLC and CCF containers, mirror recognition and the LinkFilter rules, which can hide a link or sort it into a package or category as it arrives; see The LinkGrabber and LinkFilter rules. The switch for the cover images of indexer hits is under Settings → Interface → Display: on by default, and switched off it leaves every written detail in place.
- Watched folders — a settings page of their own
- Post-processing — what category defaults control
- The LinkGrabber
- The download queue
- Docker and NAS — mounting every root as a volume