Pip, Pipenv, Poetry or Conda

Which package manager to use in 2020?


The majority of developers when they get introduced to python, most probably pip is first tool they learn to use to manage packages. I have used pip for the first couple of years working as a developer and at that time there were almost no alternatives until that has changed.

The Pip

pip comes by default with python and installing packages with pip is pretty straight-forward,

Just pip it …

$ pip install [package-name]

If you need to keep you packages organised, and you don’t want to install project packages in the user or systems path, probably you will need to use a virtual environment .

$ python3 -m venv venv

Then you need to activate it

example (linux/unix)

$ source venv/bin/activate

And then de-activate when finished

$ deactivate

Next step would be to keep track of the installed packages

$ pip freeze >> requirements.txt

And it would be of great help when someone else needed to install this project somewhere else.

Are we finished? Well, not yet, we need to make sure that we resolve our dependencies as well.

So we can use pip-tools which is a combination of pip-compile and pip-sync.

So just to install a package with pip you will need 4-5 steps to achieve that which in my opinion is a lot of hassle.


Conda is great package management tool for python, it will take care of package management and virtual environment for you.


You can install conda on MacOs, Windows or Linux.

Conda is Python agnostic (although it is written in python). The biggest advantage over the rest of package managers is that you can install pretty much install anything from C libraries to R packages or even binaries.


to create a new virtualenv

$ conda create --name venv

Installing a package

$ conda install [package-name]

What I don’t like about Conda is that it is not really minimal, it has a lot of features that I don’t use. As well you need to install conda-lock to lock package dependencies. Which I think should be provided with the main conda package.


One of my ultimate favourite tools of all time, it is really nice to use, handles virtual environments, dependencies and dependencies of dependencies as well. Furthermore, it has an outstanding (up to date) documentation.


You can install poetry on windows, mac or linux, check here.


$ poetry init

This will create pyproject.toml , your main config file for poetry

Here is an example

name = "test_project"
version = "0.1.0"
description = ""
authors = ["ahmednafies <ahmed.nafies@gmail.com>"]
python = "^3.7"
requires = ["poetry>=0.12"]
build-backend = "poetry.masonry.api"

lets install a package (e.g requests)

$ poetry add requests

You will see that requests is the installed and the version is added to pyproject.toml as well as a new file is created poetry.lock which has all of the dependencies of requests package.

category = "main"
description = "Python package for providing Mozilla's CA Bundle."
name = "certifi"
optional = false
python-versions = "*"
version = "2020.6.20"
category = "main"
description = "Universal encoding detector for Python 2 and 3"
name = "chardet"
optional = false
python-versions = "*"
version = "3.0.4"
category = "main"
description = "Internationalized Domain Names in Applications (IDNA)"
name = "idna"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "2.10"
category = "main"
description = "Python HTTP for Humans."
name = "requests"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
version = "2.24.0"
certifi = ">=2017.4.17"
chardet = ">=3.0.2,<4"
idna = ">=2.5,<3"
urllib3 = ">=1.21.1,<1.25.0 || >1.25.0,<1.25.1 || >1.25.1,<1.26"
security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"]
socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7)", "win-inet-pton"]
category = "main"
description = "HTTP library with thread-safe connection pooling, file post, and more."
name = "urllib3"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
version = "1.25.10"
brotli = ["brotlipy (>=0.6.0)"]
secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "pyOpenSSL (>=0.14)", "ipaddress"]
socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"]
content-hash = "b70f6f5e0cfc8eed2ae66f49b863ab5b47e7a8c563510179878591339113ebd2"
python-versions = "^3.7"
certifi = [
{file = "certifi-2020.6.20-py2.py3-none-any.whl", hash = "sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41"},
{file = "certifi-2020.6.20.tar.gz", hash = "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3"},
chardet = [
{file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"},
{file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"},
idna = [
{file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"},
{file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"},
requests = [
{file = "requests-2.24.0-py2.py3-none-any.whl", hash = "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898"},
{file = "requests-2.24.0.tar.gz", hash = "sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b"},
urllib3 = [
{file = "urllib3-1.25.10-py2.py3-none-any.whl", hash = "sha256:e7983572181f5e1522d9c98453462384ee92a0be7fac5f1413a1e35c56cc0461"},
{file = "urllib3-1.25.10.tar.gz", hash = "sha256:91056c15fa70756691db97756772bb1eb9678fa585d9184f24534b100dc60f4a"},

One of the greatest features of poetry is that you can separate dev dependencies (dependencies that you use only for development e.g ipython) from your production dependencies

$ poetry add ipython --dev

Now you will see that ipython is categorised as a dev dependency

name = "test_project"
version = "0.1.0"
description = ""
authors = ["ahmednafies <ahmed.nafies@gmail.com>"]
python = "^3.7"
requests = "^2.24.0"
ipython = "^7.16.1"
requires = ["poetry>=0.12"]
build-backend = "poetry.masonry.api"

And if you want to skip installing dev dependencies (e.g in production environment).

$ poetry install --no-dev

There is no need to activate/deactivate , just run it …

$ poetry run ipython

However if you want to get shell access within the virtual environment ..

$ poetry shell

To remove a package ..

$ poetry remove [package-name]

To update a package ..

$ poetry update [package-name]

The only draw back of using poetry for me is that it uses pyproejct.toml , if you use black formatter, its configuration is usually handled in pyproject.toml as well and I personally don’t prefer to have the config of my formatter and the dependencies list in the same place.


This is what I use on a regular basis. It is exactly like poetry but with few stuff that I favour more.


If you’re on MacOS, you can install Pipenv easily with Homebrew:

$ brew install pipenv

Or, if you’re using Debian Buster+:

$ sudo apt install pipenv

Or, if you’re using Fedora:

$ sudo dnf install pipenv

Or, if you’re using FreeBSD:

# pkg install py36-pipenv

When none of the above is an option:

$ pip install pipenv

Otherwise, refer to the documentation for instructions.


With pipenv you don’t need to even initialise anything.

Just install the package directly in the repo where you want pipenv to be initialised

lets install requests for example

$ pipenv install requests

You will find tow files added


name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true
requests = "*"
python_version = "3.7"

and Pipfile.lock with all of the dependencies

"_meta": {
"hash": {
"sha256": "acbc8c4e7f2f98f1059b2a93d581ef43f4aa0c9741e64e6253adff8e35fbd99e"
"pipfile-spec": 6,
"requires": {
"python_version": "3.8"
"sources": [
"name": "pypi",
"url": "https://pypi.org/simple",
"verify_ssl": true
"default": {
"certifi": {
"hashes": [
"version": "==2020.6.20"
"chardet": {
"hashes": [
"version": "==3.0.4"
"idna": {
"hashes": [
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.10"
"requests": {
"hashes": [
"index": "pypi",
"version": "==2.24.0"
"urllib3": {
"hashes": [
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'",
"version": "==1.25.10"
"develop": {}

to separating dependencies (dev and prod) ..

$ pipenv install ipython --dev

In production if you need to install package with out dev dependencies ..

$ pipenv install

If you need to install dev dependencies ..

$ pipenv install --dev

No need to activate/deactivate.

$ pipenv run ipython

If you need to access in the virtual environment ..

$ pipenv shell 

To update a package ..

$ pipenv update [package-name]

To remove a package ..

$ pipenv uninstall [package-name]


If you think using pip and virtualenv is too much of a hassle to manage python packages, this article has provided you a couple of good tools that can replace pip and virtualenv to ease up your development process.

Software Developer

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store