Plugins
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. The reference material consulted while preparing these pages is listed in the Python Reference bibliography. |
Poetry loads every installed plugin package when it starts. Plugins add commands (poetry export and poetry shell are
plugins since Poetry 2.0) or change how Poetry behaves. This page covers using and writing them with Poetry 2.5.1; the examples
ran on 2026-10-22 on Linux with CPython 3.14.6 and the official installer’s Poetry, with scratch paths shortened to …. pip has
no plugin system.
Installing a plugin into Poetry
Plugins live in Poetry’s own environment, not in the project’s. Use the installation method you installed Poetry with:
| Poetry installed with | Add | Remove |
|---|---|---|
official installer (or any) |
|
|
pipx |
|
|
pip into a venv |
|
|
self add checks that the plugin is compatible with the running Poetry before installing it and accepts the same specifications
as poetry add (constraints, git, path). The documentation warns that self add and self remove can be problematic on
Windows, where the other methods are preferred.
poetry self add poetry-plugin-shell
Using version ^1.0.1 for poetry-plugin-shell
Updating dependencies
Resolving dependencies...
Package operations: 3 installs, 0 updates, 0 removals
- Installing ptyprocess (0.7.0)
- Installing pexpect (4.9.0)
- Installing poetry-plugin-shell (1.0.1)
Writing lock file
poetry self remove poetry-plugin-shell removes it and the dependencies it brought (3 removals). The self commands keep
their own pyproject.toml and poetry.lock for Poetry’s environment, so plugins survive poetry self update; see
Installation & Self-Management.
poetry self show plugins lists what is loaded:
- poetry-plugin-export (1.10.1) Poetry plugin to export the dependencies to various formats
1 application plugin
Dependencies
- poetry (>=2.1.0,<3.0.0)
- poetry-core (>=2.1.0,<3.0.0)
- tomlkit (>=0.11.4,<1.0.0)
Plugins a project requires (2.0)
A project can declare the plugins it needs. poetry install then installs any that Poetry’s environment lacks for this project
only, under .poetry/plugins in the project directory (add .poetry/ to .gitignore):
[project]
name = "app"
version = "0.3.0"
requires-python = ">=3.10"
dependencies = ["attrs (>=25)"]
[tool.poetry]
package-mode = false
[tool.poetry.requires-plugins]
tally-plugin = {path = "../tally-plugin", develop = true}
poetry install
poetry tally-info
Creating virtualenv app in …/app/.venv
Ensuring that the Poetry plugins required by the project are available...
The following Poetry plugins are required by the project but are not installed in Poetry's environment:
- tally-plugin (*) @ file:///…/tally-plugin
Installing Poetry plugins only for the current project...
Updating dependencies
Resolving dependencies...
Package operations: 1 install, 0 updates, 0 removals
- Installing tally-plugin (0.1.0 …/tally-plugin)
Writing lock file
Updating dependencies
Resolving dependencies...
Package operations: 1 install, 0 updates, 0 removals
- Installing attrs (26.1.0)
Writing lock file
app 0.3.0: 1 main dependencies
The entries take the same forms as dependencies (">1.0", a table with path and develop = true for plugin development).
Before the install, and with --no-plugins, the command does not exist:
The requested command tally-info does not exist.
Documentation: https://python-poetry.org/docs/cli/
A project plugin can even replace the version in Poetry’s environment, but installation fails if its dependencies conflict with Poetry’s own.
Official plugins
| Plugin | What it adds |
|---|---|
|
|
|
|
|
|
Writing a plugin
A plugin is an ordinary package that depends on poetry and declares an entry point:
-
poetry.plugin: a class implementingpoetry.plugins.plugin.Plugin, whoseactivate(poetry, io)receives thePoetryobject (project, package, configuration) and can change it; -
poetry.application.plugin: a class implementingpoetry.plugins.application_plugin.ApplicationPlugin, whoseactivate(application)receives the console application and can register commands or event listeners (Cleo’sCOMMAND,SIGNAL,TERMINATEandERRORevents).
The tally-plugin used above, in full:
[project]
name = "tally-plugin"
version = "0.1.0"
description = "Adds a 'poetry tally-info' command."
requires-python = ">=3.10"
dependencies = ["poetry (>=2.0,<3.0)"]
[project.entry-points."poetry.application.plugin"]
tally-info = "tally_plugin.plugin:TallyPlugin"
[build-system]
requires = ["poetry-core>=2.0.0,<3.0.0"]
build-backend = "poetry.core.masonry.api"
# src/tally_plugin/plugin.py
from cleo.commands.command import Command
from cleo.events.console_command_event import ConsoleCommandEvent
from cleo.events.console_events import COMMAND
from cleo.events.event_dispatcher import EventDispatcher
from poetry.console.commands.install import InstallCommand
from poetry.plugins.application_plugin import ApplicationPlugin
class TallyInfoCommand(Command):
name = "tally-info"
description = "Prints the project's name, version and dependency count."
def handle(self) -> int:
poetry = self.application.poetry
package = poetry.package
self.line(f"{package.name} {package.version}: "
f"{len(package.requires)} main dependencies")
return 0
def factory() -> Command:
return TallyInfoCommand()
class TallyPlugin(ApplicationPlugin):
def activate(self, application) -> None:
application.command_loader.register_factory("tally-info", factory)
application.event_dispatcher.add_listener(COMMAND, self.report_lock)
def report_lock(
self,
event: ConsoleCommandEvent,
event_name: str,
dispatcher: EventDispatcher,
) -> None:
if not isinstance(event.command, InstallCommand):
return
locker = event.command.poetry.locker
if locker.is_locked():
count = len(locker.lock_data.get("package", []))
event.io.write_line(f"tally-plugin: poetry.lock pins {count} packages")
Because the project requires it with develop = true, editing the plugin takes effect at once (editable project plugins arrived
in 2.3). The listener runs before every install (and sync, a subclass of it):
poetry install
poetry tally-info
tally-plugin: poetry.lock pins 1 packages
Installing dependencies from lock file
No dependencies to install or update
app 0.3.0: 1 main dependencies
Rules from the documentation:
-
register commands through
command_loader.register_factoryrather thanapplication.add(…), so the command is only imported when it is used and Poetry stays fast; -
a plugin must not remove or change Poetry’s core commands;
-
there is no stable public API: plugins use Poetry internals, which can change between releases, so test against the latest release, the release branch and
mainon a schedule, and keep thepoetryconstraint tight. Poetry 2.3 deprecatedpoetry.utils._compat.metadata, which plugins often imported; useimportlib.metadata.