ModuleNotFoundError: No module named 'dotenv' (tested fix)
ModuleNotFoundError: No module named 'dotenv' means python-dotenv is not installed for the Python running your script. The import name and the package name differ. We tested both packages and the venv mix-up on Python 3.14.
1. Cause: the package is called python-dotenv
The module you import is dotenv, but the package on PyPI is python-dotenv. We ran this script in a fresh python:3-alpine container (Python 3.14.7):
pip install -q --disable-pip-version-check --root-user-action=ignore python-dotenv 2>&1 | tail -2
pip list --disable-pip-version-check 2>/dev/null | grep -i dotenv
cd /tmp && printf 'API_KEY=abc123\n' > .env
python -c "from dotenv import load_dotenv; import os; print(load_dotenv(), os.environ['API_KEY'])"
echo "--- wrong interpreter:"
python -m venv /tmp/v && /tmp/v/bin/python -c "import dotenv" 2>&1 | tail -1
Output:
python-dotenv 1.2.4
True abc123
--- wrong interpreter:
ModuleNotFoundError: No module named 'dotenv'
After pip install python-dotenv, load_dotenv() reads .env and the variable is set. The last line shows the other common cause: a different interpreter (here a fresh venv) does not see packages installed for the first one. Install with the same Python that runs your code: python -m pip install python-dotenv, and in a venv activate it first.
2. What pip install dotenv does
python -c "from dotenv import load_dotenv" 2>&1 | tail -1
echo "--- pip install dotenv"
pip install -q --disable-pip-version-check --root-user-action=ignore dotenv 2>&1 | tail -2
pip list --disable-pip-version-check 2>/dev/null | grep -i dotenv
python -c "from dotenv import load_dotenv; print('import ok')" 2>&1 | tail -1
Output:
ModuleNotFoundError: No module named 'dotenv'
--- pip install dotenv
dotenv 0.9.9
python-dotenv 1.2.4
import ok
pip show dotenv in the same container:
Version: 0.9.9
Summary: Deprecated package
Requires: python-dotenv
The dotenv package on PyPI is a placeholder marked "Deprecated package" whose only job is to depend on python-dotenv. It works today, but put python-dotenv in your requirements so you do not rely on the placeholder.
3. Imports fine but variables are None: no .env found
import os
from dotenv import load_dotenv, find_dotenv
os.chdir("/srv") # a directory with no .env in it or above it
print("find_dotenv():", repr(find_dotenv(usecwd=True)))
print("load_dotenv():", load_dotenv()) # no error, just False
print("API_KEY:", os.getenv("API_KEY"))
Output:
find_dotenv(): ''
load_dotenv(): False
API_KEY: None
load_dotenv() does not raise when it cannot find a .env file; it returns False, and os.getenv then returns None. Check the return value, or pass an explicit path: load_dotenv(Path(__file__).parent / ".env").
Related: ModuleNotFoundError vs ImportError · import from another directory · No module named 'distutils'.
Frequently asked questions
How do I fix No module named dotenv?
Run python -m pip install python-dotenv with the same interpreter (or activated venv) that runs your code.
Should I pip install dotenv or python-dotenv?
python-dotenv. The dotenv package on PyPI is a deprecated placeholder that just depends on python-dotenv.
Why is os.getenv None after load_dotenv?
load_dotenv() returns False instead of raising when it finds no .env file. Pass an explicit path or check the return value.
Written with AI assistance. Measured on 2026-10-22 in the official python:3-alpine image (Python 3.14.7): importing dotenv before and after pip install dotenv (0.9.9) and python-dotenv (1.2.4), a fresh venv, and load_dotenv() with no .env file. Every block was run verbatim and its output pasted unedited. PlainHeaders is our extension; Python and python-dotenv are free.