Skip to content

Lifecycle Rules

The lifecycle rule engine lets you define conditions to automatically identify and act on media in your library. It uses a flexible rule group structure with AND/OR logic.

A rule set is a named collection of rules and actions. Each rule set targets a specific media type (movies, series, or music).

Rules are organized into groups. Each condition (and each nested sub-group) connects to the one above it with AND or OR:

  • AND: must match together with everything above it
  • OR: matches if either side does

When a group uses a single connector throughout, this reads exactly as you’d expect — all conditions must match (AND) or any condition may match (OR). When AND and OR are mixed, conditions combine top to bottom, each connector applying to the combined result of everything above it — so A OR B AND C means (A OR B) AND C. The builder shows a hint whenever this applies, and the Logic Preview panel beside the builder always spells out the exact grouping with parentheses (hovering a condition highlights its line in the preview).

Groups can be nested to make grouping explicit — a sub-group is evaluated on its own first, then joins its parent as a single result.

Each individual rule consists of:

  1. Field — what property to evaluate (e.g., playCount, resolution, addedAt)
  2. Operator — how to compare (e.g., equals, greaterThan, before)
  3. Value — the target value

Negation is part of the operator choice: alongside each comparison the picker offers its inverse — Not Equals, Not Contains, Not Greater Than, Not Between, and so on.

Whole groups can be negated too. Every group has a NOT toggle that inverts its entire result — for example NOT (watched by Alice OR watched by Bob) matches items watched by neither. The Logic Preview shows the negation in place, and items the group would have matched are excluded instead. (Stream query groups negate through their ANY/NO quantifier rather than a NOT toggle.)

By default there is no limit. Librariarr is built to run unattended, and if your rules legitimately select thousands of items, it deletes thousands of items — that is the point of the tool, not a bug to guard against.

You can opt into a ceiling under Settings → General → Delete without asking, up to N items per run. A run that would delete more than N is held: nothing is deleted, the actions stay on the Pending page, and you execute them from there once you have looked at them. That review step is the approval — there is no separate queue to manage.

What it is for is worth being precise about. It is not a safety net for a rule you wrote wrong; a rule that selects 40 items you did not mean will happily delete 40 items under a limit of 50. It bounds the other case — where something upstream of the rule is wrong and the match set is far larger than anything you intended. Librariarr already refuses to evaluate rules whose evidence is missing (unavailable Arr metadata, unestablished play history), but those guards each cover a hazard someone found. A ceiling covers the ones nobody has found yet.

Details worth knowing:

  • Deletions only. Unmonitor, tag and search actions never count toward it and are never held.
  • Per run, across every rule set — one number for the whole execution pass.
  • Counted after the safety checks, not before. The figure is what the run would actually delete, so actions about to be cancelled anyway — the item stopped matching, it (or a sibling) is on the exception list, the item’s identity changed since it was scheduled — are not counted, and they are still cleaned up even on a run the ceiling holds.
  • All-or-nothing. Exceeding the limit holds the entire batch rather than deleting up to the limit. Acting on an arbitrary slice of a match set you already have reason to distrust is not safer.
  • It applies to manual bulk actions too — “Execute All” on the Matches page and the Query page’s actions — not just scheduled runs.
  • If you have a Discord webhook configured, a held run notifies you, so it cannot fail silently.

Over 50 fields are available for rule conditions.

Field Description Operators
playCount Number of times played equals, greaterThan, lessThan, etc.
watchedByUser Server username that played the item (Plex/Jellyfin/Emby) — multi-select equals, notEquals, contains, notContains
lastPlayedAt When last played before, after, inLastDays
addedAt When added to library before, after, inLastDays
title Media title equals, contains, matchesWildcard
parentTitle Series name (for episodes) equals, contains, matchesWildcard
year Release year equals, greaterThan, lessThan, etc.
contentRating Content rating (PG, R, etc.) equals, notEquals
rating Critic rating greaterThan, lessThan, etc.
audienceRating Audience rating greaterThan, lessThan, etc.
studio Production studio equals, contains
genre Genre(s) equals, contains
country Country of origin — multi-select (movies only) equals, contains, notContains
duration Duration in minutes greaterThan, lessThan, etc.
hasExternalId Which external-id sources the item carries (TMDB, TVDB, IMDB, MUSICBRAINZ) — multi-select equals, notEquals, contains, notContains, matchesWildcard, isNull, isNotNull
Field Description
resolution 4K, 1080P, 720P, etc.
videoCodec H.264, H.265, AV1, etc.
videoBitrate Video bitrate
videoBitDepth 8-bit, 10-bit
videoProfile Baseline, Main, High
videoFrameRate Frame rate (23.976, 24, etc.)
aspectRatio 16:9, 4:3, 2.39:1, etc.
dynamicRange SDR, HDR10, HDR10+, Dolby Vision, HLG
scanType progressive, interlaced
Field Description
audioCodec AAC, AC3, FLAC, etc.
audioChannels Channel count (2, 6, 8, etc.)
audioProfile Dolby Atmos, DTS-HD MA, etc.
audioSamplingRate Sampling rate (48000, etc.)
audioBitrate Audio bitrate
audioLanguage Audio track language
audioStreamCount Number of audio tracks
Field Description
fileSize File size (in MB)
container File container (MKV, MP4, etc.)
subtitleLanguage Subtitle track language
subtitleStreamCount Number of subtitle tracks

These fields require configured Sonarr, Radarr, or Lidarr integrations.

Field Description
foundInArr Whether the item exists in the linked *arr instance
arrMonitored Whether monitored in *arr
arrTag Tags in *arr instance
arrQualityProfile Quality profile name
arrQualityName Name of the current file’s quality (Radarr / movies only)
arrQualityCutoffMet Whether the current file meets the quality profile’s cutoff (Radarr / movies only). true once the file is at or above the cutoff, so no upgrade is pending
arrCustomFormatScore Custom format score of the movie’s current file (Radarr / movies only)
arrStatus Release/lifecycle status in *arr (e.g. released, continuing)
arrEnded Whether the series has ended (Sonarr / series only)
arrSeriesType Series type: standard, daily, or anime (Sonarr / series only)
arrRating Rating in *arr. For movies this is the IMDB rating; for series/music it is the single aggregate rating the *arr exposes
arrTmdbRating TMDB rating in *arr (Radarr / movies only — Sonarr/Lidarr expose only a single flat rating)
arrRtCriticRating Rotten Tomatoes critic rating in *arr (Radarr / movies only — Sonarr/Lidarr expose only a single flat rating)
arrOriginalLanguage Original language in *arr (not music)
arrRuntime Runtime in minutes (Radarr / movies only)
arrSizeOnDisk Size on disk in MB
arrPath File path in *arr
arrReleaseDate Digital/physical release date (Radarr / movies only)
arrInCinemasDate In-cinemas date (Radarr / movies only)
arrFirstAired First-aired date (Sonarr / series only)
arrDateAdded When the item was added to *arr
arrDownloadDate When the current file was downloaded (Radarr / movies only)
arrSeasonCount Total season count (Sonarr / series only)
arrEpisodeCount Total episode count (Sonarr / series only)
arrHasUnaired Whether the series has unaired episodes (Sonarr / series only)
arrMonitoredSeasonCount Number of monitored seasons (Sonarr / series only)
arrMonitoredEpisodeCount Number of monitored episodes (Sonarr / series only)

These fields require a configured Seerr integration.

Field Description
seerrRequested Whether requested in Seerr
seerrRequestDate When the request was made
seerrRequestCount Number of requests
seerrRequestedBy Who requested it
seerrApprovalDate When approved
seerrDeclineDate When declined
Operator Applicable Types Description
equals text, number Exact match
notEquals text, number Not an exact match
greaterThan number Greater than value
greaterThanOrEqual number Greater than or equal
lessThan number Less than value
lessThanOrEqual number Less than or equal
contains text For free-text fields (e.g. title, path): substring match (case-insensitive). For enumerable fields (e.g. quality profile, tag, codec) the operator presents a multi-select and matches if the item’s value equals any selected value (list membership, not substring).

All text comparisons are case-insensitive, including genres, labels and countries. Servers do not agree on casing — one may report Sci-Fi where another reports sci-fi, and the dropdown lists both — so a rule written against either spelling matches copies on every server. | notContains | text | Inverse of contains — same free-text vs enumerable distinction. | | matchesWildcard | text | Wildcard match (* = any characters, ? = single character) | | notMatchesWildcard | text | Does not match wildcard pattern | | before | date | Before a specific date | | after | date | After a specific date | | inLastDays | date | Within the last N days | | notInLastDays | date | More than N days ago | | between | number, date | Within an inclusive range | | isNull | text, number, date | Is Empty — the item has no value for this field (takes no value of its own) | | isNotNull | text, number, date | Is Not Empty — the item has some value for this field (takes no value of its own) |

Is Empty / Is Not Empty take no value; what counts as “empty” depends on the field’s shape:

Field shape Examples Is Empty matches
Nullable column studio, rating, lastPlayedAt, arrQualityName, arrEnded The value is missing
List genre, labels, country, arrTag, seerrRequestedBy, watchedByUser, matchedByRuleSet The list has no entries — e.g. an item that is in *arr but carries no tags
Always-present text title, arrQualityProfile The value is the empty string

Fields whose value is always present and has no meaningful “empty” reading — foundInArr, arrMonitored, seerrRequested, seerrRequestCount, playCount, isWatchlisted — don’t offer the two operators at all, because Is Not Empty on them would just match everything.

  1. Create a Rule Set: Give it a name and select the target media type
  2. Add rules: Select a field, operator, and value
  3. Group rules: Use AND/OR groups to combine conditions
  4. Nest groups: Create sub-groups for complex logic
  5. Toggle rules: Enable/disable individual rules or groups without deleting them
  6. Negate: Pick a “Not …” operator to invert a condition, or flip a group’s NOT toggle to invert the whole group
  7. Reorder: Drag rules to change their position within a group

Create a rule set with an AND group containing:

  • playCount equals 0 — Never watched
  • addedAt before 2023-01-01 — Added over a year ago
  • resolution notEquals 4K — Not 4K quality

Create a rule set with an OR group:

  • resolution equals 480P
  • resolution equals SD
  • videoCodec equals mpeg2video

Example: Watched Only By Departed Household Members

Section titled “Example: Watched Only By Departed Household Members”

Create a rule set with an AND group:

  • watchedByUser contains alice|bob — Only watched by people no longer in the household
  • watchedByUser notContains carol|dave — Never watched by current household members
  • addedAt notInLastDays 180 — Been in the library for at least 6 months

The watchedByUser field reads from the per-user play history synced from Plex / Jellyfin / Emby. “Watched by” means any play by that user, regardless of how much of the item they actually consumed. The dropdown is populated with usernames the sync has seen on your connected servers.

The Query Builder at /library/query shares its rule shape with the lifecycle engine. If you build a query that you’d like to enforce on a schedule, use Convert to Lifecycle Rule on the query builder toolbar to create a rule set without re-entering the criteria.

What the conversion does:

  • Copies the rule tree verbatim — no changes to fields, operators, or values.
  • Prompts you to pick a target library type when the query targets more than one (rule sets are scoped to a single type).
  • Drops any rules that don’t apply to the chosen library type and shows you the list before submitting. For example, when targeting Movies, any series-aggregate or music-only rules are removed.
  • Creates the new rule set with actionEnabled off and no action configured — matches will be detected on the next scheduler run, but nothing is deleted or unmonitored until you choose an action.

After conversion, you’re redirected to the new rule set’s editor so you can pick an action type, set the delay, configure tags, and re-evaluate.

An in-progress query is kept for the current browser tab, so navigating away and back doesn’t lose it. This is separate from Save, which stores a named query — the draft lives only in that tab and is cleared when you close it. Discard appears when a draft is restored; New clears the builder at any time.

Running Actions Directly from the Query Page

Section titled “Running Actions Directly from the Query Page”

For one-off cleanups you don’t want to schedule, you can run a lifecycle action on query results without creating a rule set:

  1. Pick the Arr instance(s) for the media types you want to act on in the query toolbar (Radarr for movies, Sonarr for series, Lidarr for music).
  2. Run the query, then tick the results you want to act on. Table and card views both offer a select-all control.
  3. In the Actions bar above the results, choose an action (e.g. Delete from Radarr, Unmonitor & Delete Files, Change Quality Profile), set any options it offers (target quality profile, import exclusion, Search after), optionally add or remove *arr tags, then Run action and confirm.

A progress bar tracks both the query and the action while they run. The result count line reports the total file size of all results, and the Actions bar shows the combined size of your selection — handy for gauging how much space a cleanup will reclaim before you run it.

Notes:

  • Runs immediately — there is no delay, unlike scheduled rule actions.
  • Any selection size — larger selections are split automatically into sequential batches of up to 1,000 items, and the Actions bar and confirmation dialog tell you how many. Each batch is recorded before the next starts, so a run that stops part-way loses nothing — re-run to finish the rest. (One exception: a whole-series action on more than 1,000 episodes of a single show is refused while you’re viewing individual episodes — switch to the grouped series view, which acts on the show in one unit.)
  • One Arr family per run — an action applies only to selected results of its media type (e.g. Delete from Radarr acts on selected movies); selected items of other types are skipped and reported in the result toast.
  • Before acting, the query is re-run so only items that still match are affected, and items on the Lifecycle Exceptions list are skipped automatically.
  • Actions are refused when the query’s *arr or Seerr criteria can’t actually be evaluated — no *arr server selected for the action’s media type, no enabled Seerr instance, or Seerr criteria on a music action. Without that data a rule like Found In Arr = false would match your entire library, so the run is blocked with an explanatory error.
  • Every run is recorded in the Actions history (and deletion stats) labelled Ad-hoc query action, so there’s a full audit trail even though no rule set exists.

Before executing any actions, use the Preview feature to see which media items match your rules:

  • Shows a count of matching items
  • Displays a paginated list (50 per page) with metadata
  • Updates in real time as you modify rules
  • Shows a live progress bar through each phase (fetching *arr/Seerr metadata, evaluating rules, computing matched criteria) so large libraries don’t just spin

Preview is refused whenever the rules can’t be evaluated faithfully, and the reason is shown as an error notification rather than an empty or stale result list. The same guard that pauses detection applies here, so a preview never shows matches that detection would refuse to produce:

  • *arr criteria with no enabled Sonarr/Radarr/Lidarr instance, or Seerr criteria with no enabled Seerr instance (Seerr criteria on a music rule set are refused permanently).
  • Criteria that read play activity — Watched By User, Play Count, Last Played, and the series rollups built on them — while any targeted server’s play history isn’t established yet: it has never synced, was recently cleared, or a Tracearr history import is still backfilling. Until the history is known, every item looks never-watched, so Play Count = 0 or not played in N months would match the entire library. The warning names the server and which of those applies: a server that is still importing clears itself when the import finishes (Settings → Servers shows its progress), while one where no sync has established what was played clears on the next successful watch-history sync — run one from Library → History → Refresh.

The last case also shows a “Play history not established yet” warning in the rule editor, naming the servers involved, so you can see a rule set is paused without having to run anything. It clears itself when the import finishes — no reload needed. The same warning pattern already covers a missing *arr or Seerr instance.

Saving with Run detection now reports the same thing: if detection refuses the rule set, you stay on the editor with the reason rather than being sent to Matches, where the previous run’s matches would otherwise look like the new result.

Run and Re-evaluate All on the Matches page report it too. A refused rule set keeps the matches it already had — detection preserves them deliberately — so its row is left as it was and a notification names the rule set and the reason. It is not shown as having zero matches; that would be the opposite of what happened.

Actions determine what happens to matched media. Configure them in the Actions tab of a rule set.

Action Description Requires
Delete Remove from *arr and optionally delete files Sonarr/Radarr/Lidarr
Unmonitor Stop monitoring for upgrades in *arr Sonarr/Radarr/Lidarr
Change Quality Profile Switch the *arr item to a different quality profile Sonarr/Radarr/Lidarr
Search for New Copy Trigger an *arr search for a new copy of the item Sonarr/Radarr/Lidarr
Do Nothing Track matches without taking action

Tags can be added or removed as a supplementary operation alongside any action (including Do Nothing).

This action switches a movie, series, or artist to a different quality profile in the linked *arr instance.

  • The dropdown is populated live from the selected *arr instance’s quality profiles, so it always reflects what the *arr server currently offers.
  • Items that are already on the selected profile are skipped at execution time. No update call is made and the action completes as a no-op.
  • Combining this action with arrQualityProfile rule conditions lets you upgrade or downgrade items that don’t match your desired profile (for example: “any movie whose current quality profile is SD → switch to HD-1080p”).
  • The target profile is required when the action is enabled — Save is disabled until one is selected.
  • Toggle Search for upgrade after profile change to trigger an immediate *arr search after the profile is updated. The search only fires when the profile actually changed — skipped (no-op) items don’t trigger a search.

This action triggers an *arr search for a new copy of the matched movie, series, or artist without changing monitoring, quality profile, or deleting anything. It is a standalone alternative to the Search after / Search for upgrade toggles that accompany the delete-files and quality-profile actions — use it when all you want is to kick off a fresh search.

Each action links a rule set to an *arr instance:

  1. Select the *arr integration (e.g., “My Radarr”)
  2. Choose the action type (delete, unmonitor, do nothing)
  3. Set action-specific options (e.g., delete files toggle)
  4. Optionally configure tags to add or remove
  5. Set priority — actions execute top-to-bottom

When you configure a destructive action (Delete, Delete Files, Unmonitor & Delete Files, Monitor & Delete Files) for an *arr instance, Librariarr queries that instance for its Recycle Bin Path (Settings → Media Management in Sonarr/Radarr/Lidarr).

  • If a recycle bin path is set, deleted files are sent to that path before being permanently removed (per the configured cleanup days).
  • If no path is set, deletes are immediate and unrecoverable.

When the recycle bin is disabled, Librariarr surfaces the risk in two places:

  1. An inline amber warning appears under the Action type select.
  2. On save, a confirmation modal blocks the save until you check “I understand that deletes will be permanent and unrecoverable.” The modal includes a deep link to the *arr instance’s Media Management settings so you can configure a recycle bin without leaving the page.

The acknowledgement is remembered per *arr instance for the current session — once you accept, you won’t be re-prompted for that same instance until the page is reloaded.

A rule set can keep a Plex collection in sync with its matches — useful for surfacing a “Leaving Soon” shelf to your users. In the rule editor, turn on Sync matches to a Plex collection, then pick a collection from the dropdown or choose Create new collection….

Collections are reusable, saved definitions (Plex only). Each one owns its presentation settings:

  • Collection name — the title shown in Plex.
  • Sort name (optional) — a sort title prefix (e.g., !001) to pin the collection to the top of a library.
  • Sort orderAlphabetical, Release date, or Action date.
  • Display on home screens / Display in library recommended — Plex visibility toggles.

Because the settings live on the collection (not the rule), editing them from any rule applies to every rule synced to that collection.

Multiple rule sets can target the same collection. When they do, the collection’s membership is the union of all of their matches — Librariarr never lets two rules fight over the same collection. For example, separate “4K movies leaving soon” and “unwatched series leaving soon” rules can both feed a single Leaving Soon shelf (within the same library type).

A collection is scoped to one library type (Movies, Series, or Music), since a Plex collection lives inside a single library. To use the same name for both movies and series, create two collections.

With Sort order: Action date, items are arranged soonest-scheduled-action first. When several rules feed the collection, the ordering pools the scheduled action dates of all of them, so the shelf is correctly interleaved regardless of which rule scheduled each item. (Items without a pending action are placed last.)

  • Disabling collection sync on a rule, or deleting the rule, simply detaches it — the collection is re-synced to the remaining rules’ matches. The Plex collection is removed only when it has no remaining members.
  • The collection Librariarr writes to Plex is never read back in as a library item. Collections are containers, not media, so the library sync skips them — a “Leaving Soon” shelf can’t turn into a fake movie in your Movies list, and it can never be matched by a rule.
  • Writing the collection does not trigger a library sync. Plex reports the write back as a change to the collection and to every item it tagged, and the real-time sync recognises that echo as Librariarr’s own and ignores it — so a detection run cannot cause an off-schedule full sync of the server.
  • To delete a collection definition outright, select it in the dropdown and use the trash button. You can delete it from the last rule that uses it — doing so removes the collection from that rule and deletes it from Plex. The button is disabled (and the API refuses) only while other rules still reference it, so remove it from those first.

Troubleshooting: matches exist but the collection is empty

Section titled “Troubleshooting: matches exist but the collection is empty”

The Matches page reads directly from the database, but the Plex collection is populated by a separate sync step that pushes each matched item to Plex by its rating key. If a rule has matches yet the Plex collection shows 0 items, check System > Logs for a line like Failed to sync collection "…" for library … — it now names the exact Plex request, HTTP status, and Plex’s own error message so you can tell what was rejected. Common causes:

  • The Plex server has no stored machine identifier. Collections are written using the server’s identifier, so a server added without it is skipped (you’ll see a … has no machineId warning). Re-add the server through the Plex picker to store it.
  • Stale rating keys. If Plex regenerated its rating keys (a library rebuild, “Optimize database”, or removing and re-adding the section), the stored keys no longer resolve and Plex rejects the update. Run a full sync of that library so Librariarr relearns the current keys.
  • The matched copy lives on a different (or non-Plex) server. A movie present on more than one server resolves to whichever copy was matched; only its own server’s library can hold it in a Plex collection.

As a safety measure, Librariarr will not empty or delete a collection when its rules matched items but none of them resolved to that Plex library — it leaves the collection intact, so a resolution problem never silently wipes a shelf. When the matched items belong to that library but couldn’t be resolved to Plex rating keys (stale series titles, for example), a warning is logged; when they simply live in another library or server — normal in multi-library setups — the skip is only visible in debug logs. A collection is only removed when its rules genuinely match nothing.

Rules are evaluated in two steps:

  1. Step 1 — Local data: Rules based on your media’s own properties (resolution, play count, dates, file size, etc.) are evaluated first using your database — this is fast.

  2. Step 2 — External data: Rules based on Sonarr, Radarr, Lidarr, or Seerr data (tags, quality profiles, monitored status, requests) require live lookups to those services, so they run after Step 1 narrows down the results.

For Series rule sets, the Series Scope toggle controls the unit of evaluation:

  • Series scope on — the rule is evaluated against the whole show, and an action applies to the entire series. Every episode is a member of the match.
  • Series scope off — the rule is evaluated against individual episodes, then results are grouped by show. A member-scoped action (such as Delete Files Only) acts only on the episodes that matched.

Some fields are series-aggregate fields — availableEpisodeCount, watchedEpisodeCount, watchedEpisodePercentage, lastEpisodeAiredAt, lastEpisodeAddedAt, latestEpisodeViewDate, and seriesLastPlayedAt (Series Last Played). These describe the show as a whole and can only be computed across every episode, so a rule that references one is always evaluated at the series level — even with Series Scope off.

Series Last Played is the most recent play date across all episodes (the max of every episode’s last-played date). Use it to find shows nobody has touched in a while — e.g. Series Last Played is not in the last 365 days matches only series where every episode was last played over a year ago. This differs from the per-episode Last Played field (which would match a series as long as it has any old episode, even if another episode was watched yesterday) and from Latest Episode View Date (the play date of the newest episode by number — “did they watch the latest episode?”).

When Series Scope is off and your rule mixes an aggregate field with a per-episode field (for example, available episode count ≥ 20 and resolution = 4K), the show first has to qualify on the aggregate, and then a member-scoped file delete acts only on the episodes that individually satisfy the per-episode conditions (here, just the 4K episodes) — not every episode of the series. With Series Scope on, the same rule deletes the whole series.

Lifecycle processing runs on two independent schedules (configured in Settings → Scheduling):

  • Detection: Evaluates rules and identifies matching media
  • Execution: Performs configured actions on matched media

Both can be run manually via the Run Now button at any time.

The Pending Actions page displays a running total of data deleted by lifecycle actions — including the total bytes removed and the number of completed actions. This gives you visibility into how much storage the lifecycle system has reclaimed.

  • Stats are computed from completed actions that have recorded file sizes
  • Click the reset button to start counting from zero — historical action records are unaffected
  • After a reset, only actions completed after the reset point are included in the totals
  • *arr actions require the corresponding integration to be configured and reachable
  • Rules using integration data are slower and scale with the number of matches
  • File size rules accept input in MB but are stored and compared in bytes
  • Wildcard matching uses * (any characters) and ? (single character), not regex