If you run Radarr, Sonarr, or any of the *arr apps, you've probably written a quick script to automate something. Bulk imports, library cleanup, monitoring. And you've probably hit the same wall: the APIs are big, undocumented in practice, and every app has slightly different conventions.
I got tired of writing raw fetch calls and guessing at response shapes, so I built Tsarr: a fully type-safe TypeScript client and CLI that covers the entire Servarr ecosystem.
What it does
Tsarr provides auto-generated TypeScript clients for:
- Radarr (movies)
- Sonarr (TV series)
- Lidarr (music)
- Readarr (books)
- Prowlarr (indexers)
- Bazarr (subtitles)
Every client is generated directly from the official Swagger/OpenAPI specs, so types are always accurate and up-to-date. When the *arr devs update their API, Tsarr follows automatically.
How it works under the hood
Each *arr app ships an OpenAPI/Swagger spec that describes their full API. Tsarr uses @hey-api/openapi-ts to generate typed TypeScript clients from those specs.
The flow looks like this:
- Fetch the latest OpenAPI specs from each *arr app's GitHub repo
- Run
@hey-api/openapi-tsto generate fully typed clients (request types, response types, enums, everything) - Bundle it all into one package with modular imports per app
- The CLI layer wraps those same clients with citty for the command-line interface
Because the generation is automated, keeping up with API changes is just a matter of re-running the generator. Renovate handles dependency bumps, and semantic-release cuts new versions automatically when PRs merge.
No hand-written API types. No manual maintenance. If the official spec changes, the next build catches it.
Use it as an SDK
import { RadarrClient, SonarrClient } from 'tsarr';
const radarr = new RadarrClient({
baseUrl: 'http://localhost:7878',
apiKey: 'your-api-key'
});
// Full type safety: autocomplete, type checking, the works
const movies = await radarr.getMovies();
const status = await radarr.getSystemStatus();
You get proper TypeScript types for every request and response. No more guessing what fields a movie object has.
Use it as a CLI
# Install globally
npm install -g tsarr
# Setup
tsarr config init
# Manage your library from the terminal
tsarr radarr movie list
tsarr radarr movie search --term "Interstellar"
tsarr sonarr series list
tsarr prowlarr indexer list
# Check all connections at once
tsarr doctor
# JSON output for scripting
tsarr radarr movie list --json | jq '.[] | .title'
The CLI supports table output for humans and JSON for scripts. Shell completions included for bash, zsh, and fish.
Why I built this
I self-host everything on a Kubernetes cluster at home. When you manage multiple *arr instances, automation isn't optional. I also run an AI assistant that manages my homelab, and it works way better with CLIs than raw APIs. Being able to say "add Interstellar to Radarr" and have it run tsarr radarr movie add behind the scenes is a game changer.
So I needed:
- Type safety so I catch API changes at compile time, not at 3 AM when my automation breaks
- One package instead of six different libraries for six different apps
- CLI access because sometimes you just want to check something from the terminal without opening a browser
Nothing like this existed for TypeScript. Managarr is a great Rust TUI for interactive management, but if your stack is Node.js/TypeScript and you want to build automation, you were on your own.
Installation
Available everywhere:
# npm
npm install tsarr
# Homebrew
brew install robbeverhelst/tsarr/tsarr
# Docker
docker run --rm ghcr.io/robbeverhelst/tsarr doctor
# AUR (Arch Linux)
yay -S tsarr-bin
# Nix
nix profile install github:robbeverhelst/tsarr?dir=packaging/nix
# Or grab a standalone binary, no runtime needed
curl -L https://github.com/robbeverhelst/tsarr/releases/latest/download/tsarr-linux-x64 -o tsarr
What you can build with it
Some things I use it for:
- Bulk movie imports: feed it a list, let it add everything with proper quality profiles
- Library audits: find movies without subtitles, series with missing episodes
- Monitoring scripts: check queue status, disk space, indexer health in cron jobs
- Cross-app automation: when Sonarr grabs a series, trigger Bazarr to fetch subtitles
The CLI is also great for quick checks without leaving the terminal:
# What's in my download queue right now?
tsarr radarr queue list --table
# Any indexer issues?
tsarr prowlarr indexer list --table
It's open source
MIT licensed. Contributions welcome.
- GitHub: robbeverhelst/Tsarr
- npm: tsarr
- Docs: robbeverhelst.github.io/Tsarr
If you run any *arr apps and write TypeScript, give it a try. Issues and PRs welcome, especially if you find edge cases in specific API endpoints.
What's your *arr automation setup like? I'd love to hear what people are building.
Top comments (0)