Entry Points & Console Scripts
Entry points register CLI commands and plugin hooks at install time. [project.scripts] creates console commands; [project.entry-points] enables plugin discovery.
Search across all documentation pages
Entry points register CLI commands and plugin hooks at install time. [project.scripts] creates console commands; [project.entry-points] enables plugin discovery.
[project.scripts]
myapp = "myapp.cli:main"
[project.entry-points."myapp.plugins"]
json = "myapp.plugins.json:JsonPlugin"When to reach for this:
[project]
name = "invoice-cli"
version = "0.1.0"
[project.scripts]
invoice = "invoice_cli.main:cli"
[project.entry-points."invoice.exporters"]
csv = "invoice_cli.exporters:CSVExporter"
pdf = "invoice_cli.exporters:PDFExporter"# src/invoice_cli/main.py
import click
from importlib.metadata import entry_points
@click.group()
def cli():
"""Invoice management CLI."""
pass
@cli.command()
@click.option("--format", default="csv")
def export(format: str):
eps = entry_points(group="invoice.exporters")
exporter = eps[format].load()
exporter().run()
def main():
cli()uv pip install -e .
invoice export --format csvWhat this demonstrates:
project.scripts installs invoice command to PATHimportlib.metadataclick or typer handles CLI parsing inside main| Type | Config | Result |
|---|---|---|
| Console scripts | [project.scripts] | Executable in bin/ |
| Plugin groups | [project.entry-points."group"] | importlib discovery |
| GUI scripts | [project.gui-scripts] | GUI launcher (rare) |
main() guard - fine for entry points but needed for python -m. Fix: add if __name__ == "__main__" for module execution.| Alternative | Use When | Don't Use When |
|---|---|---|
python -m myapp | No install needed | Global CLI expected |
| pipx | Isolated CLI install | Library + CLI combo |
| Shell script wrapper | Legacy deploy | Cross-platform package |
scripts = CLI commands. entry-points = plugin discovery groups.
from importlib.metadata import entry_points; ep.load()() in pytest.
Yes. They register entry points in their pyproject.toml under your group name.
pipx installs the package and exposes console_scripts to an isolated venv on PATH.
Use short, unique names. invoice not cli.
uv respects PEP 621 entry points identically to pip.
importlib.metadata.entry_points(group="console_scripts").
Not standard. Plugins register statically in their own packages.
[project.entry-points] replaces [options.entry_points] in setup.cfg.
Multiple lines in [project.scripts], one per command.
Stack versions: This page was written for Python 3.14.0, FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, and uv 0.6+.
Reviewed by Chris St. John·Last updated Jul 19, 2026