Jellarr
Declarative configuration engine for Jellyfin — apply and sync server settings from YAML via the Jellyfin API.
Install / Use
/learn @venkyr77/JellarrREADME
Jellarr
Jellarr is an open-source tool designed to simplify declarative configuration management for Jellyfin media servers. Inspired by Configarr's approach to *arr stack automation, Jellarr uses Jellyfin's official REST API to safely apply configuration changes through version-controlled YAML files.
By streamlining server configuration, Jellarr saves time, enhances consistency across environments, and reduces manual intervention.
Why Jellarr?
Managing Jellyfin configuration becomes painful at scale:
- Configuration drift across dev/staging/prod environments
- No version control for settings changes
- Manual clicking through web UI doesn't scale to multiple servers
- No automation for configuration-as-code workflows
Existing solutions have limitations. While declarative-jellyfin pioneered declarative Jellyfin configuration, it takes a risky approach:
- Directly manipulates XML files and SQLite databases
- Stops/starts Jellyfin service multiple times during configuration
- Reimplements Jellyfin's internal UUID generation in bash
- NixOS-only with hardcoded systemd and path dependencies
- Breaks when Jellyfin changes internals (example issue)
Jellarr takes a different approach:
- ✅ API-based — Uses Jellyfin's official REST API, never touches internal files or databases
- ✅ Zero service interruption — Jellyfin keeps running, no restarts required
- ✅ Cross-platform — Works on Docker, bare metal, any OS (not just NixOS)
- ✅ Type-safe — OpenAPI-generated types catch errors at build time
- ✅ Future-proof — Relies on stable API contracts, not reverse-engineered internals
- ✅ Production-ready — Idempotent, safe to run anytime via cron/systemd timers
Quick Start
# With Nix
nix run github:venkyr77/jellarr/v0.0.1
# With Docker
docker pull ghcr.io/venkyr77/jellarr:v0.0.1
# Download binary (requires Node.js 24+)
./jellarr-v0.0.1
Example config (config/config.yml):
version: 1
base_url: "http://localhost:8096"
system:
enableMetrics: true
pluginRepositories:
- name: "Jellyfin Official"
url: "https://repo.jellyfin.org/releases/plugin/manifest.json"
enabled: true
encoding:
enableHardwareEncoding: true
hardwareAccelerationType: "vaapi"
vaapiDevice: "/dev/dri/renderD128"
Installation
Nix Flake (Recommended)
Add to your flake.nix:
{
inputs.jellarr.url = "github:venkyr77/jellarr";
outputs = { self, nixpkgs, jellarr, ... }: {
nixosConfigurations.myhost = nixpkgs.lib.nixosSystem {
modules = [
jellarr.nixosModules.default
({ config, ... }: {
services.jellarr = {
enable = true;
user = "jellyfin";
group = "jellyfin";
environmentFile = config.sops.templates.jellarr-env.path;
config = {
base_url = "http://localhost:8096";
system.enableMetrics = true;
};
};
})
];
};
};
}
Or run directly:
JELLARR_API_KEY=your_api_key nix run github:venkyr77/jellarr/v0.0.1
Docker (Recommended)
docker pull ghcr.io/venkyr77/jellarr:v0.0.1
With docker-compose:
services:
jellarr:
image: ghcr.io/venkyr77/jellarr:v0.0.1
container_name: jellarr
environment:
- JELLARR_API_KEY=${JELLARR_API_KEY}
- TZ=Etc/UTC
volumes:
- ./config:/config
restart: "no"
Bundle Download
Download from releases (requires Node.js 24+):
curl -LO https://github.com/venkyr77/jellarr/releases/download/v0.0.2/jellarr-v0.0.2.cjs
JELLARR_API_KEY=your_api_key node jellarr-v0.0.2.cjs --configFile path/to/config.yml
Note: Requires Node.js 24+ installed on your system.
Export Existing Configuration (Experimental)
Already have a configured Jellyfin server? Use dump to export its current
configuration as a starting point:
JELLARR_API_KEY=your_api_key jellarr dump --baseUrl http://localhost:8096 > config.yml
This exports system settings, encoding options, libraries, branding, users (without passwords), and plugin configurations. Edit the output to:
- Remove fields you don't want to manage
- Add
passwordorpasswordFileto users - Remove any default values you don't need
See dumped-example.yml for sample output.
Configuration
Jellarr uses a YAML configuration file (default: config/config.yml).
System Configuration
version: 1
base_url: "http://localhost:8096"
system:
enableMetrics: true # Enable Prometheus metrics endpoint
pluginRepositories:
- name: "Jellyfin Official"
url: "https://repo.jellyfin.org/releases/plugin/manifest.json"
enabled: true
trickplayOptions:
enableHwAcceleration: true
enableHwEncoding: true
Encoding Configuration
version: 1
base_url: "http://localhost:8096"
encoding:
enableHardwareEncoding: true
hardwareAccelerationType: "vaapi" # none, amf, qsv, nvenc, v4l2m2m, vaapi, videotoolbox, rkmpp
vaapiDevice: "/dev/dri/renderD128"
# or qsv device
qsvDevice: "/dev/dri/renderD128"
hardwareDecodingCodecs:
- h264
- hevc
- mpeg2video
- vc1
- vp8
- vp9
- av1
enableDecodingColorDepth10Hevc: true
enableDecodingColorDepth10HevcRext: true
enableDecodingColorDepth12HevcRext: true
enableDecodingColorDepth10Vp9: true
allowHevcEncoding: false
allowAv1Encoding: false
Library Configuration
version: 1
base_url: "http://localhost:8096"
library:
virtualFolders:
- name: "Movies"
collectionType: "movies"
libraryOptions:
pathInfos:
- path: "/data/movies"
- name: "TV Shows"
collectionType: "tvshows"
libraryOptions:
pathInfos:
- path: "/data/tv"
Branding Configuration
version: 1
base_url: "http://localhost:8096"
branding:
loginDisclaimer: |
Configured by <a href="https://github.com/venkyr77/jellarr">Jellarr</a>
customCss: |
@import url("https://cdn.jsdelivr.net/npm/jellyskin@latest/dist/main.css");
splashscreenEnabled: false
User Management
version: 1
base_url: "http://localhost:8096"
users:
# Regular user with plaintext password (development only)
- name: "regular-user"
password: "secure-password"
# Regular user with password file (production recommended)
- name: "viewer-user"
passwordFile: "/run/secrets/viewer-password"
# Admin user with policy configuration
- name: "admin-user"
passwordFile: "/run/secrets/admin-password"
policy:
isAdministrator: true
loginAttemptsBeforeLockout: 3
Password Security:
- plaintext password: Use
passwordfield for development/testing only - password file: Use
passwordFilefor production - file contains only the plaintext password (whitespace is trimmed) - Exactly one required: Each user must specify either
passwordorpasswordFile(not both)
sops-nix Integration:
{
sops.secrets = {
jellarr-api-key.sopsFile = ../../../../secrets/jellarr-api-key;
viewer-user-password.sopsFile = ../../../../secrets/viewer-user-password;
admin-user-password.sopsFile = ../../../../secrets/admin-user-password;
};
services.jellarr = {
enable = true;
environmentFile = config.sops.templates.jellarr-env.path;
config = {
base_url = "http://localhost:8096";
users = [
{
name = "viewer-user";
passwordFile = config.sops.secrets.viewer-user-password.path;
}
{
name = "admin-user";
passwordFile = config.sops.secrets.admin-user-password.path;
}
];
};
};
}
Startup Configuration
version: 1
base_url: "http://localhost:8096"
system: {}
startup:
completeStartupWizard: true # Mark startup wizard as complete
Useful for automated deployments where you want to skip the interactive startup wizard.
Plugin Management
version: 1
base_url: "http://localhost:8096"
plugins:
# Install plugin by name (from configured repositories)
- name: "Trakt"
# Install and configure plugin
- name: "Trakt"
configuration:
TraktUsers:
- ExtraLogging: true
# Multiple plugins
- name: "Playback Reporting"
- name: "Fanart"
configuration:
EnableImages: true
How it works:
- Plugins are installed from repositories configured in
system.pluginRepositories - Plugin names must match exactly (case-sensitive)
- The
configurationfield accepts arbitrary key-value pairs specific to each plugin - Only specified configuration fields are updated; unspecified fields are preserved
- Plugin configurations are applied after installation, allowing newly installed plugins to be configured in the same run
Finding plugin configuration keys:
To discover available configuration options for a plugin, you can query the Jellyfin API:
# Get plugin ID
curl -s -H "X-Emby-Token: $API_KEY" \
"http://localhost:8096/Plugins" | jq '.[] | select(.Name == "Trakt")'
# Get plugin configuration
curl -s -H "X-Emby-Token: $API_KEY" \
"http://localhost:8096/Plugins/{pluginId}/Configuration"
Secret Management
With sops-nix (nix only)
{
sops = {
secrets.jellarr-api-key.sopsFile = ./secrets/jellarr.env;
templates.jellarr-env = {
content = ''
JELLARR_API_KEY=${config.sops.placeholder.jellarr-api-key}
'';
owner = config.services.jellarr.user;
group = config.services.jellarr.group;
};
};
services.jellarr = {
enable = true;
environmentFile = config.sops.templates.jellarr-env.path;
c
