# Music Assistant Builtin Providers vs Regular Providers: Loading Mechanisms and Lifecycle Management

> Learn how Music Assistant loads builtin providers instantly vs regular providers needing pip installation. Understand their lifecycle and configuration differences.

- Repository: [Music Assistant/server](https://github.com/music-assistant/server)
- Tags: internals
- Published: 2026-06-21

---

**Music Assistant loads builtin providers instantly without pip installation, while regular providers require dependency resolution via pip before import, with both types sharing the same base class but differing in lifecycle management and UI configuration options.**

Music Assistant (music-assistant/server) distinguishes between builtin providers shipped with the core application and regular external providers that require additional dependencies. Understanding how the system loads these different provider types reveals important architectural decisions around startup performance, fault isolation, and runtime configuration.

## Manifest Configuration Distinguishes Provider Types

### The Builtin Flag in manifest.json

In [`music_assistant/providers/builtin/manifest.json`](https://github.com/music-assistant/server/blob/main/music_assistant/providers/builtin/manifest.json), providers declare `"builtin": true` to indicate they ship with the core Music Assistant codebase. This flag signals that the provider requires no external packages and typically sets `"allow_disable": false` and `"multi_instance": false` to prevent users from disabling the provider or creating multiple instances.

### Requirements for Regular Providers

Regular providers like Spotify omit the `"builtin"` flag and instead specify `"requirements": ["package>=1.0"]` in their [`manifest.json`](https://github.com/music-assistant/server/blob/main/manifest.json) files. When Music Assistant loads these providers, it must first install the listed dependencies before importing the module, creating a clear distinction in the loading pipeline.

## Discovery and Loading Pipeline

### Manifest Discovery in mass.py

When Music Assistant starts, `Mass.__load_provider_manifests()` (located at line 1115 in [`music_assistant/mass.py`](https://github.com/music-assistant/server/blob/main/music_assistant/mass.py)) walks the `music_assistant/providers` directory and constructs `ProviderManifest` objects from each [`manifest.json`](https://github.com/music-assistant/server/blob/main/manifest.json). The loader sets `manifest.builtin = True` for builtin providers while attaching requirement lists to regular provider manifests.

### Conditional Import Logic in util.py

The `load_provider_module()` function in [`music_assistant/helpers/util.py`](https://github.com/music-assistant/server/blob/main/music_assistant/helpers/util.py) (line 1043) handles the actual import differently based on provider type:

```python
async def load_provider_module(domain: str, requirements: list[str]) -> ProviderModuleType:
    # For builtin providers: requirements is empty, skip pip install

    # For regular providers: invoke pip/uv to install requirements first

    await pip_install(requirements)  # Only runs if requirements list is non-empty

    return importlib.import_module(f"music_assistant.providers.{domain}")

```

Builtin providers bypass the pip installation step entirely, allowing immediate import from the local codebase.

## Instantiation and Lifecycle Management

### Shared Base Class Implementation

Both provider types inherit from `music_assistant.models.provider.Provider`, which provides uniform behavior for logging, configuration updates, and feature checks. After loading the module via `load_provider_module()`, `Mass._load_provider()` (line 1039 in [`music_assistant/mass.py`](https://github.com/music-assistant/server/blob/main/music_assistant/mass.py)) instantiates the provider class identically for both types:

```python
prov_mod = await load_provider_module(domain, manifest.requirements)
provider = prov_mod.Provider(
    mass=self,
    manifest=manifest,
    config=conf,
    supported_features=set(manifest.features),
)

```

### Runtime Behavioral Differences

Despite sharing instantiation logic, the providers differ in runtime behavior:

- **Installation**: Builtin providers require zero setup time, while regular providers trigger `pip install` on first load
- **Disable/Enable**: Builtin providers with `"allow_disable": false` appear as permanent in the UI, whereas regular providers can be toggled by users
- **Instance Management**: Builtin providers use fixed `instance_id = "builtin"`, while regular providers support multiple instances (e.g., multiple Spotify accounts) via unique instance IDs
- **Reload Behavior**: Builtin providers handle configuration updates without full reloads, while regular providers often require complete restarts to re-authenticate with external services

## Practical Implementation Examples

Creating a builtin provider requires an empty requirements array and specific flags:

```json
{
  "type": "music",
  "domain": "my_builtin",
  "name": "My Built-in Provider",
  "requirements": [],
  "builtin": true,
  "allow_disable": false,
  "multi_instance": false
}

```

Regular providers specify external dependencies:

```json
{
  "type": "music",
  "domain": "example",
  "name": "Example Provider",
  "requirements": ["example-api>=1.2"],
  "builtin": false,
  "allow_disable": true,
  "multi_instance": true
}

```

## Summary

- **Builtin providers** ship with Music Assistant, require no pip installation, and typically cannot be disabled or duplicated
- **Regular providers** require dependency installation via `load_provider_module()` in [`music_assistant/helpers/util.py`](https://github.com/music-assistant/server/blob/main/music_assistant/helpers/util.py) before import
- Both provider types share the same base class (`music_assistant.models.provider.Provider`) and instantiation logic in `Mass._load_provider()`
- The [`manifest.json`](https://github.com/music-assistant/server/blob/main/manifest.json) flags `"builtin"`, `"allow_disable"`, and `"multi_instance"` control UI behavior and lifecycle management
- Discovery occurs through `Mass.__load_provider_manifests()` in [`music_assistant/mass.py`](https://github.com/music-assistant/server/blob/main/music_assistant/mass.py), which processes all provider directories uniformly

## Frequently Asked Questions

### What makes a provider "builtin" in Music Assistant?

A builtin provider is defined by the presence of `"builtin": true` in its [`manifest.json`](https://github.com/music-assistant/server/blob/main/manifest.json) file and an empty `"requirements"` array. These providers reside within the `music_assistant/providers` directory and ship with the core codebase, requiring no external package installation.

### Can builtin providers be disabled in the UI?

Typically no. Builtin providers usually set `"allow_disable": false` in their manifest, which prevents the UI from showing a disable toggle. This ensures core functionality remains available even if external dependencies fail.

### How does dependency installation work for regular providers?

When loading a regular provider, Music Assistant calls `load_provider_module()` in [`music_assistant/helpers/util.py`](https://github.com/music-assistant/server/blob/main/music_assistant/helpers/util.py), which checks the `requirements` list from the manifest. If dependencies are present, it invokes pip (or uv) to install them before importing the module via `importlib`.

### Do builtin and regular providers share the same code structure?

Yes. Both implement the same `Provider` base class from [`music_assistant/models/provider.py`](https://github.com/music-assistant/server/blob/main/music_assistant/models/provider.py) and expose identical interfaces for configuration, feature handling, and media playback. The differences lie only in the loading mechanism and lifecycle configuration, not in the implementation pattern.