Introduction to PDM: A Python Project and Dependency Manager
PDM is a modern Python package and dependency manager prioritizing compliance with PEP standards and developer experience.
It aims to bring best practices from other language ecosystems to Python, offering a more intuitive and efficient way to manage projects and dependencies.
This article will introduce you to PDM, explain its core concepts and advantages, and guide you through implementing PDM best practices in your Python development workflow.
Prerequisites
To follow along with this tutorial, you'll need a recent version of Python installed on your system (Python 3.13 or newer is recommended). While PDM can help manage Python versions, having at least one Python installation will simplify getting started.
Why use PDM?
Before diving into PDM, let's understand why it significantly improves over traditional Python project management approaches. Here's what makes PDM unique:
PEP-621 compatible project management: PDM fully supports the official Python packaging standards, using
pyproject.toml
as the single source of truth for your project configuration.Virtual environment automation: PDM automatically creates and manages isolated environments for your projects without requiring explicit activation.
Deterministic dependency resolution: PDM ensures reproducible builds through its advanced dependency resolver and lock file system.
Powerful plugin system: PDM can be extended with plugins, allowing you to customize and enhance your workflow based on specific project needs.
A good way to understand PDM is to consider it a blend of pip
, virtualenv
, and poetry
, combined into a unified package management and workflow tool that follows modern Python standards.
Installing PDM
This section guides you through installing PDM on your machine.
The recommended way to install PDM on Linux is by using the official installation script(On macOS, you can easily install it with Homebrew):
curl -sSL https://pdm-project.org/install-pdm.py | python3 -
The installer will place PDM in your $HOME/.local/bin
.
Make sure this location is in your PATH. Add the following line to your shell configuration file (like .bashrc
, .zshrc
, or .profile
):
export PATH="$HOME/.local/bin:$PATH"
Then, apply the changes:
source ~/.bashrc
To verify that PDM has been installed successfully, run:
pdm --version
PDM, version 2.22.4
This output confirms that PDM has been installed successfully and is ready for use.
Getting started with PDM
Now that PDM is installed, let's explore its core functionality. PDM simplifies Python project management by automating virtual environments and dependency installation while strictly adhering to modern Python packaging standards.
To start a new project with PDM, create a project directory and navigate into it:
mkdir pdm-demo && cd pdm-demo
Initialize a new PDM project with:
pdm init
This command launches an interactive setup that prompts you to configure key project details, such as the Python interpreter, project name, version, license, author information, and dependencies:
Creating a pyproject.toml for PDM...
Please enter the Python interpreter to use
0. cpython@3.13 (/opt/homebrew/bin/python3)
1. cpython@3.13 (/opt/homebrew/bin/python3.13)
2. cpython@3.12 (/opt/homebrew/bin/python3.12)
3. cpython@3.9 (/usr/bin/python3)
4. cpython@3.13 (/opt/homebrew/Cellar/python@3.13/3.13.2/Frameworks/Python.framework/Versions/3.13/bin/python3.13)
Please select (0): 1
Virtualenv is created successfully at /Users/stanley/pdm-demo/.venv
Project name (pdm-demo):
Project version (0.1.0):
Do you want to build this project for distribution(such as wheel)?
If yes, it will be installed by default when running `pdm install`. [y/n] (n):
License(SPDX name) (MIT):
Author name (Your name):
Author email (youremail@gmail.com):
Python requires('*' to allow any) (==3.13.*):
Project is initialized successfully
Once completed, PDM generates a pyproject.toml
file containing your project's metadata and configuration.
This file is the central project descriptor, defining dependencies, package settings, and other relevant details.
Unlike traditional workflows that require manually creating and activating a virtual environment, PDM automates this process, streamlining project setup.
To install a package, simply run:
pdm add requests
Adding packages to default dependencies: requests
0:00:03 🔒 Lock successful.
Changes are written to pyproject.toml.
Synchronizing working set with resolved packages: 5 to add, 0 to update, 0 to remove
✔ Install idna 3.10 successful
✔ Install certifi 2025.1.31 successful
✔ Install requests 2.32.3 successful
✔ Install urllib3 2.3.0 successful
✔ Install charset-normalizer 3.4.1 successful
0:00:01 🎉 All complete! 5/5
During installation, PDM automatically creates a virtual environment if one doesn’t exist, installs the package along with its dependencies, and updates both pyproject.toml and pdm.lock to track dependencies.
You can also install multiple packages at once:
pdm add numpy pandas matplotlib
Or specify version constraints:
pdm add "django>=4.2"
As mentioned earlier, one of PDM’s key features is that you don’t need to manually activate virtual environments. To test your installation, create a simple Python script:
import requests
response = requests.get("https://api.github.com/users/pdm-project")
data = response.json()
print(f"PDM GitHub repository: {data['html_url']}")
print(f"PDM has {data['public_repos']} public repositories")
Run it using PDM:
pdm run python app.py
PDM GitHub repository: https://github.com/pdm-project
PDM has 19 public repositories
This automatically uses the correct virtual environment, making it easy to work with multiple projects without environment conflicts.
You've now seen how PDM simplifies dependency management and project setup. It removes many of the manual steps required with traditional tools while ensuring that your project follows modern Python best practices.
Managing dependencies with PDM
Now, let's dive deeper into PDM's powerful dependency management capabilities that make package installation, version control, and environment synchronization more reliable.
PDM's dependency management approach is built around two key files:
pyproject.toml
: Declares your project's dependencies with version specificationspdm.lock
: Records the exact versions of all dependencies and sub-dependencies
When you add a package using PDM, it updates both files automatically:
pdm add fastapi
This command installs FastAPI and updates your project configuration:
[project]
name = "pdm-demo"
version = "0.1.0"
description = ""
authors = [
{name = "Your Name", email = "your.email@example.com"},
]
dependencies = ["requests>=2.32.3", ..., "fastapi>=0.115.11"]
requires-python = "==3.13.*"
readme = "README.md"
license = {text = "MIT"}
[tool.pdm]
distribution = false
Meanwhile, PDM also creates a detailed lock file that captures the exact versions of FastAPI and all its sub-dependencies. This ensures that anyone else working on your project will get exactly the same environment.
PDM provides fine-grained control over version constraints. For example:
pdm add "sqlalchemy>=2.0.0" "pydantic<2.0.0"
This adds SQLAlchemy with a minimum version of 2.0.0 and Pydantic with a maximum version below 2.0.0.
To update dependencies to their latest compatible versions:
pdm update
Or update specific packages:
pdm update fastapi pydantic
If you no longer need a package, remove it with:
pdm remove fastapi
This not only uninstalls the package but also updates the pyproject.toml
and pdm.lock
files to keep your dependency declarations in sync with what's installed.
When collaborating with a team or setting up your project on a new machine, you don't need to install each package individually. Simply clone the repository with the pyproject.toml
and pdm.lock
files, then run:
pdm install
This installs the exact versions specified in the lock file, ensuring a consistent environment across all development machines and deployment targets.
PDM also makes it easy to run commands within the project's environment without activation:
pdm run python -c "import requests; print(requests.__version__)"
2.32.3
Using PDM's modern approach to dependency management helps maintain consistency across development, testing, and production environments, reducing compatibility issues that often arise in Python projects.
Working with dependency groups in PDM
Most Python projects require different sets of dependencies for various purposes. PDM provides a clean solution to this challenge through dependency groups, which allow you to categorize and manage dependencies based on their usage.
Dependency groups offer several advantages:
- Clear separation between runtime and development dependencies
- Ability to install only what's needed for specific tasks
- Improved project organization and documentation
- Reduced environment size in production deployments
As you have already seen, when you add a package with pdm add
, it goes into the main dependencies section in pyproject.toml
:
pdm add sqlalchemy
This results in:
[project]
dependencies = [
"sqlalchemy>=2.0.39",
]
However, tools used only during development—like testing frameworks, type checkers, or linters—should be kept separate. PDM makes this easy with the --dev
or -d
flag:
pdm add --dev pytest mypy black
This creates a new optional dependency group named "dev":
...
[dependency-groups]
dev = [
"pytest>=8.3.5",
"mypy>=1.15.0",
"black>=25.1.0",
]
Development dependencies won't be included in your package's distribution metadata, making them perfect for tools only needed during development.
You can create multiple development dependency groups:
pdm add -dG test pytest pytest-cov
pdm add -dG lint flake8 black
This results in:
...
[dependency-groups]
...
test = [
"pytest>=8.3.5",
"pytest-cov>=6.0.0",
]
lint = [
"flake8>=7.1.2",
"black>=25.1.0",
]
For dependencies that should be included in your package metadata (like optional features), use the -G/--group
option instead:
pdm add -G web flask jinja2
This adds dependencies to the optional dependencies section:
...
[project.optional-dependencies]
web = [
"flask>=3.1.0",
"jinja2>=3.1.6",
]
...
Using dependencies from specific groups
To run commands using packages from specific groups, use pdm run
. For example, to execute a package from development dependencies:
pdm run pytest
============================================================== test session starts ==============================================================
platform darwin -- Python 3.13.2, pytest-8.3.5, pluggy-1.5.0
rootdir: /Users/stanley/pdm-demo
configfile: pyproject.toml
plugins: cov-6.0.0
collected 0 items
============================================================= no tests ran in 0.01s =============================================================
To install dependencies selectively, use the appropriate pdm install
command.
Install only production dependencies:
pdm install --prod
Install production dependencies along with a specific optional group:
pdm install -G web
Different command combinations will install different sets of dependencies:
pdm install
installs production + all development dependenciespdm install -G web
installs production + "web" optional group + all development dependenciespdm install -G test
installs production + only the "test" development grouppdm install --prod
installs production dependencies only
Organizing dependencies into logical groups with PDM improves project maintainability by defining package usage and optimizing environments for specific tasks.
Python version management with PDM
Managing Python versions across different projects is a common challenge for developers. PDM simplifies this by providing built-in Python version management capabilities that ensure your project always runs with the correct Python version.
PDM's approach to Python version management is based on two key concepts:
- Declaring Python version requirements in
pyproject.toml
- Automatically selecting an appropriate Python interpreter based on those requirements
When you initialize a PDM project, you specify the Python version requirements:
[project]
requires-python = "==3.13.*"
This example indicates that your project is compatible with any 3.13.x version. When creating a new project, PDM suggests a default value based on your selected Python version.
PDM will automatically select an appropriate Python interpreter from those available on your system. To see which Python version PDM is using for your project:
pdm info
PDM version:
2.22.4
Python Interpreter:
/Users/stanley/pdm-demo/.venv/bin/python (3.13)
Project Root:
/Users/stanley/pdm-demo
Local Packages:
If you need to use a different Python version, ensure it's compatible with your project's requires-python
specification.
For example, if you try to switch to Python 3.12 with a project that requires 3.13:
pdm use python3.12
[NoPythonVersion]: No Python interpreter matching requires-python="==3.13.*" is found.
To switch Python versions successfully, update the requires-python
value in your pyproject.toml
file to >=3.12
.
[project]
name = "pdm-demo"
version = "0.1.0"
...
requires-python = ">=3.12"
....
Now switch the Python version like this:
pdm use python3.12
INFO: Using the first matched interpreter.
Virtualenv is created successfully at /Users/stanley/pdm-demo/.venv
Using Python interpreter: /Users/stanley/pdm-demo/.venv/bin/python
(3.12)
This ensures that your project's dependencies remain compatible with the Python version you're using.
Installing Python versions with PDM
A key feature of PDM is its ability to install different Python versions directly.
To see all available Python versions for installation:
pdm python install --list
cpython@3.13.2
cpython@3.13.1
cpython@3.13.0
cpython@3.12.9
cpython@3.12.8
cpython@3.12.7
...
cpython@3.11.11
cpython@3.11.10
cpython@3.10.4
cpython@3.10.3
cpython@3.8.13
cpython@3.8.12
pypy@3.11.11
pypy@3.10.19
pypy@3.10.14
...
pypy@3.9.15
pypy@3.8.16
pypy@3.8.15
PDM can also automatically choose the best Python version based on your project's requires-python
. For example, to automatically install and use the highest compatible version:
pdm python install
Or to install the minimum compatible version:
pdm python install --min
These features make PDM a convenient tool for managing Python environments efficiently.
Final thoughts
This article has explored PDM's key features to help modernize your Python development workflow. PDM combines modern dependency management, project structure, and Python version handling into a single, standards-compliant tool.
For more details, visit the official PDM documentation.
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
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.comor submit a pull request and help us build better products for everyone.
See the full list of amazing projects on github