Skip to main content
Media libraries are the foundation of Jellyfin’s content organization system. Each library represents a collection of media files of a specific type (movies, TV shows, music, etc.) that Jellyfin scans, indexes, and makes available for streaming.

Library Structure

Jellyfin organizes media into a hierarchical structure:
1

Root Folder

The AggregateFolder serves as the root container for all libraries. It aggregates all virtual folders configured by the administrator.
2

Virtual Folders

Each library is represented as a virtual folder with a specific collection type (Movies, TV Shows, Music, Books, etc.).
3

Physical Paths

Virtual folders map to one or more physical paths on disk where media files are stored.
4

Media Items

Individual files are resolved into typed items (Movie, Episode, Audio, etc.) with associated metadata.

Collection Types

Jellyfin supports several collection types, each with specialized handling:
  • Individual movie files
  • Movie folders with multiple versions/editions
  • Extras (trailers, behind-the-scenes, deleted scenes)
  • Multiple video formats

Library Manager

The LibraryManager is the central service for managing media libraries:
Emby.Server.Implementations/Library/LibraryManager.cs
public class LibraryManager : ILibraryManager
{
    private readonly ILogger<LibraryManager> _logger;
    private readonly IItemRepository _itemRepository;
    private readonly IUserManager _userManager;
    private readonly IFileSystem _fileSystem;
    private readonly NamingOptions _namingOptions;
    
    private readonly FastConcurrentLru<Guid, BaseItem> _cache;
    
    public AggregateFolder RootFolder
    {
        get
        {
            if (_rootFolder is null)
            {
                lock (_rootFolderSyncLock)
                {
                    _rootFolder ??= CreateRootFolder();
                }
            }
            return _rootFolder;
        }
    }
    
    public event EventHandler<ItemChangeEventArgs>? ItemAdded;
    public event EventHandler<ItemChangeEventArgs>? ItemUpdated;
    public event EventHandler<ItemChangeEventArgs>? ItemRemoved;
}
The LibraryManager uses an LRU cache to improve performance when accessing frequently requested items, reducing database queries.

Media Scanning Process

When Jellyfin scans a library, it follows a multi-stage process:
1

File Discovery

The file system is traversed to discover media files based on naming conventions and file extensions.
public BaseItem? ResolvePath(
    FileSystemMetadata fileInfo,
    Folder? parent = null,
    IDirectoryService? directoryService = null)
{
    // Resolve files into BaseItem objects
}
2

Item Resolution

Resolvers determine the type of each media item (Movie, Episode, Audio, etc.).Jellyfin includes specialized resolvers:
  • MovieResolver - Identifies movie files
  • SeriesResolver - Identifies TV series folders
  • EpisodeResolver - Parses episode information from filenames
  • AudioResolver - Identifies audio tracks
3

Metadata Extraction

Metadata is extracted from:
  • Embedded tags (ID3, MP4, MKV metadata)
  • File naming patterns (episode numbers, years, etc.)
  • NFO files (Kodi-compatible XML metadata)
4

Provider Fetching

External metadata providers are queried:
  • TMDb (movies and TV shows)
  • MusicBrainz (music)
  • Open Subtitles (subtitles)
  • Local metadata providers
5

Database Persistence

Items and their metadata are saved to the database.
await _itemRepository.SaveItems(items, cancellationToken)
    .ConfigureAwait(false);
6

Post-Scan Tasks

Additional processing tasks run after the scan:
  • Image extraction and processing
  • Chapter image generation
  • People/actor validation

Naming Conventions

Jellyfin uses the Emby.Naming library to parse media files:

TV Show Naming

TV Shows/
  ├── Show Name (2020)/
  │   ├── Season 01/
  │   │   ├── Show Name - S01E01 - Episode Title.mkv
  │   │   ├── Show Name - S01E02 - Episode Title.mkv
  │   │   └── Show Name - S01E03-E04 - Multi-Episode.mkv
  │   ├── Season 02/
  │   │   └── ...
  │   └── tvshow.nfo

Movie Naming

Movies/
  ├── Movie Name (2021)/
  │   ├── Movie Name (2021).mkv
  │   ├── Movie Name (2021)-trailer.mp4
  │   ├── movie.nfo
  │   └── poster.jpg
  ├── Another Movie (2022).mp4

Music Naming

Music/
  ├── Artist Name/
  │   ├── Album Name (2020)/
  │   │   ├── 01 - Track Name.flac
  │   │   ├── 02 - Track Name.flac
  │   │   ├── cover.jpg
  │   │   └── album.nfo
Jellyfin supports multiple naming patterns. See the NamingOptions class for the full list of supported formats.

Library Options

Each library can be configured with specific options:
MediaBrowser.Model/Configuration/LibraryOptions.cs
public class LibraryOptions
{
    // Enable/disable metadata providers
    public bool EnablePhotos { get; set; }
    public bool EnableRealtimeMonitor { get; set; }
    public bool EnableChapterImageExtraction { get; set; }
    public bool ExtractChapterImagesDuringLibraryScan { get; set; }
    
    // Metadata downloaders
    public string[] MetadataSavers { get; set; }
    public string[] DisabledLocalMetadataReaders { get; set; }
    public string[] LocalMetadataReaderOrder { get; set; }
    
    // Content preferences
    public string[] PreferredMetadataLanguage { get; set; }
    public string PreferredImageLanguage { get; set; }
    
    // Path settings
    public string[] PathInfos { get; set; }
}

Real-Time Monitoring

Jellyfin can monitor libraries for changes in real-time:
MediaBrowser.Controller/Library/ILibraryMonitor.cs
public interface ILibraryMonitor
{
    void Start();
    void Stop();
    
    void ReportFileSystemChangeBeginning(string path);
    void ReportFileSystemChangeComplete(string path, bool refreshPath);
}
When real-time monitoring is enabled:
  • File system watchers detect new, modified, or deleted files
  • Changes are debounced to avoid excessive scanning
  • Only affected items are refreshed
Real-time monitoring can be resource-intensive on large libraries or network shares. Consider using scheduled scans for network-mounted storage.

Item Resolution

The resolution process uses a priority-based system of resolvers:
MediaBrowser.Controller/Library/ItemResolveArgs.cs
public class ItemResolveArgs
{
    public Folder? Parent { get; set; }
    public FileSystemMetadata FileInfo { get; set; }
    public string Path { get; set; }
    public LibraryOptions LibraryOptions { get; set; }
    public CollectionType? CollectionType { get; set; }
    
    public bool IsDirectory => FileInfo?.IsDirectory ?? false;
    public bool IsVf => Parent is AggregateFolder;
}
Resolvers are executed in priority order:
public void AddParts(
    IEnumerable<IResolverIgnoreRule> rules,
    IEnumerable<IItemResolver> resolvers,
    IEnumerable<IIntroProvider> introProviders,
    IEnumerable<IBaseItemComparer> itemComparers,
    IEnumerable<ILibraryPostScanTask> postScanTasks)
{
    EntityResolutionIgnoreRules = rules.ToArray();
    EntityResolvers = resolvers.OrderBy(i => i.Priority).ToArray();
    MultiItemResolvers = EntityResolvers.OfType<IMultiItemResolver>().ToArray();
}

Metadata Providers

Metadata is fetched from multiple sources:
  • NFO files: Kodi-compatible XML metadata
  • Embedded metadata: Tags in media files
  • Image files: poster.jpg, fanart.jpg, etc.

Image Processing

Jellyfin processes and caches images for optimal delivery:
  • Primary images: Posters, covers
  • Backdrops: Background artwork
  • Logos: Transparent overlays
  • Thumbnails: Chapter images, episode stills
public interface IImageProcessor
{
    Task<string> ProcessImage(ImageProcessingOptions options);
    string GetImageCacheTag(BaseItem item, ItemImageInfo image);
    ImageDimensions GetImageDimensions(BaseItem item, ItemImageInfo image);
}
Images are automatically resized and cached based on client requirements to optimize bandwidth and loading times.

Library Events

The LibraryManager emits events for library changes:
// Subscribe to library events
library.ItemAdded += (sender, args) => 
{
    _logger.LogInformation("Item added: {Name}", args.Item.Name);
};

library.ItemUpdated += (sender, args) =>
{
    _logger.LogInformation("Item updated: {Name}", args.Item.Name);
};

library.ItemRemoved += (sender, args) =>
{
    _logger.LogInformation("Item removed: {Name}", args.Item.Name);
};
These events are propagated to connected clients via WebSocket.

Next Steps

Architecture

Understand Jellyfin’s overall architecture

Users & Authentication

Learn about user management

Plugins

Extend library functionality with plugins

API Reference

Access library data via the API