SkillAgentSearch skills...

Jellarr

Declarative configuration engine for Jellyfin — apply and sync server settings from YAML via the Jellyfin API.

Install / Use

/learn @venkyr77/Jellarr

README

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 password or passwordFile to 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 password field for development/testing only
  • password file: Use passwordFile for production - file contains only the plaintext password (whitespace is trimmed)
  • Exactly one required: Each user must specify either password or passwordFile (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 configuration field 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
View on GitHub
GitHub Stars145
CategoryDevelopment
Updated21h ago
Forks10

Languages

TypeScript

Security Score

100/100

Audited on Mar 29, 2026

No findings