Back to Scaling Python Applications guides

Getting Started with Poetry

Stanley Ulili
Updated on March 11, 2025

Poetry is a modern dependency management and packaging tool for Python that simplifies project setup, dependency resolution, and package distribution. It creates a smooth workflow that handles virtual environments, package installations, and project scaffolding in one cohesive toolchain.

This article will guide you through Poetry's essential features, explain its benefits over traditional tools, and demonstrate how to optimize your Python development workflow.

Prerequisites

Before exploring Poetry, ensure you have a recent version of Python installed on your system, which is Python 3.13 or higher. You should also know concepts like virtual environments and basic Python package management.

Why use Poetry?

Before diving into Poetry, let's understand why it significantly improves over traditional Python package management approaches. Here's what makes Poetry unique:

  • Unified dependency management: While pip requires separate tools for environments and lockfiles, Poetry handles dependencies, virtual environments, and package publishing in a single tool
  • Deterministic builds: Poetry uses a sophisticated dependency resolver that creates lockfiles ensuring identical environments across different machines
  • Project isolation: Poetry automatically manages virtual environments, eliminating the manual venv activation and deactivation process
  • Modern packaging standards: Poetry embraces pyproject.toml as the configuration standard, replacing outdated setup.py and requirements files with a cleaner, more structured approach

Think of Poetry as an all-in-one solution that combines the functionality of pip, virtualenv, and setuptools while adding powerful features like dependency resolution and lockfile generation.

Throughout this tutorial, you'll discover how these features work together to simplify your Python workflow and make package management more reliable.

Installing Poetry

In this section, you will install Poetry on your machine.

While Poetry requires Python to work, it manages Python projects independently of your system Python. To verify you have Python installed, run:

 
python3 --version

You should see output similar to:

 
Python 3.13.2

The recommended method to install Poetry is through its official installer script:

 
curl -sSL https://install.python-poetry.org | python3 -

This command will download and install Poetry to ~/.local/bin by default on Unix-based systems.

You can verify the successful installation by executing:

 
poetry --version
Output
Poetry (version 2.1.1)

If the poetry command isn't recognized, add Poetry to your PATH with:

 
export PATH="$HOME/.local/bin:$PATH"

This output confirms that Poetry is installed correctly and ready to use.

Getting started with Poetry

Now that Poetry is installed, let's explore its core functionality. At its foundation, Poetry is a dependency and environment manager that handles project initialization, virtual environments, and package installation through a single, intuitive interface.

Poetry provides two main ways to start a project: creating a new one from scratch, or initializing an existing directory. Let's start by creating a new project:

 
poetry new poetry-demo

This creates a directory named poetry-demo. Navigate into it:

 
cd poetry-demo

Check the complete project structure using the tree command:

 
tree
Output
poetry-demo
├── README.md
├── pyproject.toml
├── src
│   └── poetry_demo
│       └── __init__.py
└── tests
    └── __init__.py

4 directories, 4 files

The pyproject.toml file is the heart of your project. It defines metadata, dependencies, build requirements, and other configuration options. When you create a new project, Poetry generates a file that looks similar to this:

pyproject.toml
[project]
name = "poetry-demo"
version = "0.1.0"
description = ""
authors = [
    {name = "Your Name",email = "your.email@example.com"}
]
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
]

[tool.poetry]
packages = [{include = "poetry_demo", from = "src"}]


[build-system]
requires = ["poetry-core>=2.0.0,<3.0.0"]
build-backend = "poetry.core.masonry.api"

Poetry automatically creates the directory structure needed for a proper Python package:

  • A README.md file for project documentation
  • A package directory (with the same name as your project but using underscores instead of hyphens)
  • A tests directory for your test files

This structure follows Python best practices, immediately preparing your project for development. Notice that Poetry assumes your package contains code in a directory with the same name as your project (but with underscores instead of hyphens) located in the root of your project.

In the following sections, you'll explore how to add dependencies to this project and manage your development environment.

Now, create a simple Python file to test your setup. Create a file named app.py:

app.py
import requests

response = requests.get("https://python-poetry.org")
print(f"Poetry website status code: {response.status_code}")
print("Poetry makes Python dependency management elegant!")

To run this file using the Poetry-managed environment, use:

 
poetry run python app.py
Output

Poetry website status code: 200
Poetry makes Python dependency management elegant!`

This workflow means you no longer need to remember to activate environments or worry about dependency conflicts. Poetry handles everything behind the scenes, ensuring a consistent and isolated development environment.

Managing dependencies with Poetry

In the previous section, you learned how to create a Poetry project and install basic dependencies. Now, let's explore how Poetry simplifies ongoing dependency management through its powerful commands and lockfile system.

Unlike traditional pip-based workflows, Poetry provides a complete suite of commands for adding, removing, and updating dependencies while maintaining consistent environments.

To add a new dependency to your project, use the add command:

 
poetry add pandas
Output
Using version ^2.2.3 for pandas

Updating dependencies
Resolving dependencies... (5.0s)

Package operations: 6 installs, 0 updates, 0 removals

  - Installing six (1.17.0)
  - Installing numpy (2.2.3)
  - Installing pytz (2025.1)
  - Installing tzdata (2025.1)
  - Installing python-dateutil (2.9.0.post0)
  - Installing pandas (2.2.3)

Writing lock file

This command:

  • Adds pandas to your pyproject.toml file with an appropriate version constraint
  • Resolves all dependencies, including transitive ones
  • Updates the poetry.lock file to ensure reproducible installations
  • Installs the packages into your virtual environment

Poetry easily handles complex dependency trees, resolving potential conflicts before they become problems. If you need a specific version, use:

 
poetry add "django>=5.1"

This ensures you get Django 5.1 or newer while maintaining compatibility with other packages in your project.

To remove packages you no longer need:

 
poetry remove pandas
Output

Updating dependencies
Resolving dependencies... (0.1s)

Package operations: 0 installs, 0 updates, 5 removals

  - Removing numpy (2.2.3)
  - Removing pandas (2.2.3)
  - Removing python-dateutil (2.9.0.post0)
  - Removing pytz (2025.1)
  - Removing six (1.17.0)

Writing lock file

Poetry removes the requested package and any dependencies that are no longer required, keeping your environment clean.

When you need to update dependencies to their latest compatible versions:

 
poetry update

This updates all packages to the latest versions allowed by the constraints in your pyproject.toml, then regenerates the lock file.

For a more targeted update of specific packages:

 
poetry update pandas

One of Poetry's most powerful features is its lock file. When you clone a project with Poetry, you can guarantee identical environments across machines by simply running:

 
poetry install

This uses the poetry.lock file to install the exact versions of all packages, eliminating "works on my machine" problems. If the lock file doesn't exist, Poetry will generate one based on the constraints in pyproject.toml.

To see what packages are installed in your current environment:

 
poetry show
Output

asgiref  3.8.1 ASGI specs, helper code, and adapters
django   5.1.7 A high-level Python web framework that encourages rapid development and clean, pragmatic design.
sqlparse 0.5.3 A non-validating SQL parser.

For a dependency tree that shows relationships between packages:

 
poetry show --tree
Output
django 5.1.7 A high-level Python web framework that encourages rapid development and clean, pragmatic design.
├── asgiref >=3.8.1,<4
├── sqlparse >=0.3.1
└── tzdata *

This comprehensive approach to dependency management ensures your Python projects remain consistent, reproducible, and free from dependency conflicts.

Managing dependency groups in Poetry

In the previous section, we explored basic dependency management with Poetry. While adding dependencies directly to the main section is sufficient for simple projects, more complex applications benefit from organizing dependencies into groups based on their purpose.

Building on our poetry-demo project, let's see how Poetry's dependency groups feature helps organize project dependencies more effectively.

Let's start by adding a testing framework to a dedicated development group:

 
poetry add --group dev pytest
Output

Using version ^8.3.5 for pytest

Updating dependencies
Resolving dependencies... (2.2s)

Package operations: 4 installs, 0 updates, 0 removals

  - Installing iniconfig (2.0.0)
  - Installing packaging (24.2)
  - Installing pluggy (1.5.0)
  - Installing pytest (8.3.5)

Writing lock file

With this command, Poetry automatically creates a development dependency group in your pyproject.toml:

 
[tool.poetry.group.dev.dependencies]
pytest = "^8.3.5"

This separation is powerful - it allows you to:

  • Keep your production environment lean by installing only necessary dependencies
  • Organize tools by their purpose
  • Install specific groups only when needed

Let's expand the project by adding more development tools:

 
poetry add --group dev black mypy
Output
Using version ^25.1.0 for black
Using version ^1.15.0 for mypy

Updating dependencies
Resolving dependencies... (3.4s)

Package operations: 7 installs, 0 updates, 0 removals

  - Installing click (8.1.8)
  - Installing mypy-extensions (1.0.0)
  - Installing pathspec (0.12.1)
  - Installing platformdirs (4.3.6)
  - Installing typing-extensions (4.12.2)
  - Installing black (25.1.0)
  - Installing mypy (1.15.0)

Writing lock file

Now your development group includes code formatting and type checking tools:

 
[tool.poetry.group.dev.dependencies]
pytest = "^8.3.5"
black = "^25.1.0"
mypy = "^1.15.0"

Beyond development tools, you can create custom groups for other purposes. For example, create a documentation group:

 
poetry add --group docs sphinx sphinx-rtd-theme

Your pyproject.toml now contains three distinct dependency groups:

pyproject.toml
...
[tool.poetry.group.dev.dependencies]
pytest = "^8.3.5"
black = "^25.1.0"
mypy = "^1.15.0"


[tool.poetry.group.docs.dependencies]
sphinx = "^8.2.3"
sphinx-rtd-theme = "^3.0.2"

When installing dependencies, you can choose which groups to include:

 
# Install all dependencies including dev and docs groups
poetry install --with dev,docs

# Install only main dependencies and dev tools, but not docs
poetry install --with dev

# Install only main dependencies, no groups
poetry install --without dev,docs

For production deployments, you typically want only the main dependencies:

 
poetry install --only main

This installs just pendulum and its dependencies, resulting in a lean production environment without testing, linting, or documentation tools.

When running commands with Poetry, you can use tools from specific groups without manually activating environments:

 
# Run pytest from the dev group
poetry run pytest

# Run black from the dev group
poetry run black poetry_demo/

# Build documentation using sphinx from the docs group
poetry run sphinx-build docs _build

Organizing dependencies into purpose-specific groups makes your project more maintainable, with more precise separation between production dependencies and development tools.

This approach reduces installation time, prevents unnecessary packages in production, and makes it easier for contributors to understand the purpose of each dependency.

Final thoughts

This article explored how Poetry simplifies Python development by managing dependencies, virtual environments, and packaging in one intuitive tool. See the official Poetry documentation to learn more.

Poetry isn't the only modern tool available. You might also explore uv, another promising alternative for faster and simpler dependency management.

Thanks for reading!

Author's avatar
Article by
Stanley Ulili
Stanley Ulili is a technical educator at Better Stack based in Malawi. He specializes in backend development and has freelanced for platforms like DigitalOcean, LogRocket, and AppSignal. Stanley is passionate about making complex topics accessible to developers.
Got an article suggestion? Let us know
Next article
How to Manage Multiple Python Versions With pyenv
Learn how to use `pyenv` to manage multiple Python versions effortlessly. This comprehensive guide covers installation, version switching, project-specific environments, virtual environments, and development tool management. Optimize your Python workflow with `pyenv` and eliminate version conflicts.
Licensed under CC-BY-NC-SA

This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

Make your mark

Join the writer's program

Are you a developer and love writing and sharing your knowledge with the world? Join our guest writing program and get paid for writing amazing technical guides. We'll get them to the right readers that will appreciate them.

Write for us
Writer of the month
Marin Bezhanov
Marin is a software engineer and architect with a broad range of experience working...
Build on top of Better Stack

Write a script, app or project on top of Better Stack and share it with the world. Make a public repository and share it with us at our email.

community@betterstack.com

or submit a pull request and help us build better products for everyone.

See the full list of amazing projects on github