Documents
Poetry Plugins vs Entry Points
Poetry Plugins vs Entry Points
Type
Document
Status
Published
Created
Mar 21, 2026
Updated
Mar 21, 2026
Updated by
Dosu Bot

Difference Between Poetry Plugins and Entry Points#

Overview#

If you've read that "Poetry supports arbitrary plugins which work similarly to setuptools entry points" and found it confusing, you're not alone. The term "plugin" in Poetry is overloaded with two distinct meanings:

  1. [tool.poetry.plugins] section - Declares standard Python entry points in your package (the same as setuptools entry points)
  2. Poetry's plugin system - Extends Poetry itself with new commands or functionality

The key insight: Poetry plugins (meaning #2) use entry points (meaning #1) to register themselves. The [tool.poetry.plugins] section is not exclusively for Poetry plugins—it's for declaring any entry points your package exposes.

Key Distinction#

Entry Points via [tool.poetry.plugins]#

When you use [tool.poetry.plugins], you're declaring standard Python entry points:

Poetry's Plugin System#

Poetry also has its own plugin system for extending Poetry itself:

How They Relate#

Poetry plugins ARE registered using entry points, but the confusion arises because:

  • The [tool.poetry.plugins] section is for YOUR package to expose entry points
  • Poetry's own plugins use that same mechanism to register with Poetry

The Conversion Process#

During package building, Poetry reads plugin declarations and writes them as standard entry points:

  1. Poetry-core's Factory reads both [project.entry-points] and [tool.poetry.plugins] sections
  2. They are stored in the package's entry_points property
  3. During wheel building, they're written to entry_points.txt in the wheel's .dist-info directory

Important: There is no actual "conversion" - Poetry simply passes through the plugin definitions in the standard setuptools format.

Configuration Examples#

Declaring Entry Points in Your Package#

Use entry points when you want other applications or tools to discover your package's functionality. This is useful for plugin systems, command-line tools, and framework extensions.

# Recommended: Using project.entry-points (PEP 621)
[project.entry-points."my_app.plugins"]
my_plugin = "my_package.module:PluginClass"

# Deprecated but still supported: Using tool.poetry.plugins
[tool.poetry.plugins."my_app.plugins"]
my_plugin = "my_package.module:PluginClass"

The format is: entry_point_name = "module.path:object"

  • "my_app.plugins" is the entry point group (you define this for your plugin system)
  • my_plugin is the name of this specific entry point
  • "my_package.module:PluginClass" points to the Python object to load

Console Scripts Shortcut#

[tool.poetry.scripts] is a shortcut for [tool.poetry.plugins."console_scripts"]. Both create command-line executables that are installed when your package is installed.

# These are equivalent:
[tool.poetry.scripts]
mycommand = "mypackage.mymodule:my_function"

[tool.poetry.plugins."console_scripts"]
mycommand = "mypackage.mymodule:my_function"

When users install your package, they can run mycommand from the command line, which will execute my_function() from mypackage.mymodule.

Creating a Poetry Plugin#

To extend Poetry itself (not your application), declare an entry point in the poetry.application.plugin or poetry.plugin group:

[project.entry-points."poetry.application.plugin"]
my-poetry-command = "my_poetry_plugin:MyApplicationPlugin"

This registers a plugin that Poetry will load when it starts. See the Poetry plugins documentation for details on implementing plugin classes.

Using Entry Points to Load Plugins in Your Application#

Once you've declared entry points in your package, other applications can discover and load them using Python's standard importlib.metadata module.

Basic Example#

from importlib.metadata import entry_points

# Discover all entry points in the "main_app.plugins" group
for entry_point in entry_points(group="main_app.plugins"):
    if entry_point.name in ["plugin_name"]:
        # Load the entry point (imports and returns the object)
        entry_point.load()

Practical Example: Registry Pattern with Auto-Discovery#

A common use case is the Registry design pattern, where plugins need to be imported so their decorators can register classes. Here's a complete example:

Plugin package's pyproject.toml:

[tool.poetry.plugins."main_app.plugins"]
my_plugin = "my_plugin_package.plugin_module"

Main application's __init__.py:

from importlib.metadata import entry_points

# Auto-discover and load all registered plugins
for entry_point in entry_points(group="main_app.plugins"):
    # Loading the entry point imports the module,
    # which triggers decorator-based registration
    entry_point.load()

Plugin module (my_plugin_package/plugin_module.py):

from main_app.registry import register

@register
class MyPluginClass:
    """This class is automatically registered when the module is imported"""
    pass

This pattern allows plugins to be automatically discovered and loaded at application startup without hardcoding their imports.

Summary Table#

Feature[tool.poetry.plugins]Poetry's Plugin System
PurposeDeclare entry points in YOUR packageExtend Poetry itself
Discoverable byAny tool using importlib.metadataPoetry
Entry point groupAny arbitrary grouppoetry.plugin or poetry.application.plugin
Syntax[tool.poetry.plugins."group"] or [project.entry-points."group"]Same, but specific groups

Additional Notes#