Skip to main content
`Ctrl`+`K`

# Plugin Development

Beets plugins are Python modules or packages that extend the core functionality of beets. The plugin system is designed to be flexible, allowing developers to add virtually any type of features to beets.

For instance you can create plugins that add new commands to the command-line interface, listen for events in the beets lifecycle or extend the autotagger with new metadata sources.

## Basic Plugin Setup

A beets plugin is just a Python module or package inside the `beetsplug` namespace [1] package. To create the basic plugin layout, create a directory called `beetsplug` and add either your plugin module:

    beetsplug/
    └── myawesomeplugin.py

or your plugin subpackage

    beetsplug/
    └── myawesomeplugin/
        ├── __init__.py
        └── myawesomeplugin.py

Attention

You do not need to add an `__init__.py` file to the `beetsplug` directory. Python treats your plugin as a namespace package automatically, thus we do not depend on `pkgutil`-based setup in the `__init__.py` file anymore.

The meat of your plugin goes in `myawesomeplugin.py`. Every plugin has to extend the `beets.plugins.BeetsPlugin` abstract base class [2] . For instance, a minimal plugin without any functionality would look like this:

    # beetsplug/myawesomeplugin.py
    from beets.plugins import BeetsPlugin

    class MyAwesomePlugin(BeetsPlugin):
        pass

Attention

If your plugin is composed of intermediate `beets.plugins.BeetsPlugin` subclasses, make sure that your plugin is defined last in the namespace. We only load the last subclass of `beets.plugins.BeetsPlugin` we find in your plugin namespace.

To use your new plugin, you need to package [3] your plugin and install it into your `beets` (virtual) environment. To enable your plugin, add it it to the beets configuration

    # config.yaml
    plugins:
      - myawesomeplugin

and you’re good to go!

[1]

Check out this article and this Stack Overflow question if you haven’t heard about namespace packages.

[2]

Abstract base classes allow us to define a contract which any plugin must follow. This is a common paradigm in object-oriented programming, and it helps to ensure that plugins are implemented in a consistent way. For more information, see for example pep-3119.

[3]

There are a variety of packaging tools available for python, for example you can use setuptools or hatchling.

## More information

For more information on writing plugins, feel free to check out the following resources:

- Add Commands to the CLI
- Listen for Events
- Extending the Autotagger
  - Overview
  - Metadata lookup
  - ID-based lookups
  - Best practices
  - Migration guidance
- Further Reading
  - Read Configuration Options
  - Add Path Format Functions and Fields
  - Extend MediaFile
  - Add Import Pipeline Stages
    - Extend the Query Syntax
  - Flexible Field Types
  - Logging
  - Append Prompt Choices