Skip to content

Virtual Envs, pip, uv, and Poetry

npm/package.json → pip/venv/pyproject.toml

Section titled “npm/package.json → pip/venv/pyproject.toml”

Package management is where Python’s tooling history is most visible. Node has one model: npm installs into node_modules, package.json declares dependencies, and package-lock.json locks exact versions. Python has three layers you need to understand: the interpreter itself, the isolation layer (venv), and then the package manager on top.

Run this in your terminal:

Terminal window
# Create a virtual environment in the .venv folder
python3 -m venv .venv
# Activate it — you must do this every new terminal session
source .venv/bin/activate # macOS / Linux
# .venv\Scripts\activate.bat # Windows CMD
# .venv\Scripts\Activate.ps1 # Windows PowerShell
# Confirm which python is active
which python # should point to .venv/bin/python
# Deactivate
deactivate

Once activated, pip install X installs only into .venv. Add .venv/ to your .gitignore.

TypeScript
# npm classic workflow
npm install express # adds to package.json + node_modules
npm install -D jest # dev dependency
npm install # install from package.json
npm ci # clean install from lock file (CI)
# package.json excerpt:
# {
# "dependencies": { "express": "^4.18.2" },
# "devDependencies": { "jest": "^29.0.0" }
# }
Python
# pip classic workflow
pip install requests # installs to active venv
pip install pytest --upgrade # install/upgrade dev dep
pip freeze > requirements.txt # snapshot all installed versions
pip install -r requirements.txt # reproduce from snapshot
# requirements.txt excerpt:
# requests==2.31.0
# certifi==2024.2.2
# charset-normalizer==3.3.2

requirements.txt is the oldest approach. It works, but it has no distinction between direct and transitive dependencies. The modern replacement is pyproject.toml.

uv (by Astral, the ruff team) is a Rust-powered replacement for pip and venv combined. It is 10–100× faster than pip and handles virtual environments automatically.

Terminal window
# Install uv (once, globally)
curl -LsSf https://astral.sh/uv/install.sh | sh
# Create a new project (generates pyproject.toml + .venv)
uv init my-project
cd my-project
# Add a dependency (updates pyproject.toml + uv.lock)
uv add fastapi
# Add a dev dependency
uv add --dev pytest ruff mypy
# Sync environment from pyproject.toml (like npm ci)
uv sync
# Run a command inside the venv without activating
uv run python main.py
uv run pytest

Layer 4: Poetry — the npm-like experience

Section titled “Layer 4: Poetry — the npm-like experience”

Poetry was the first tool to unify project metadata, dependency resolution, and virtual environment management into one ergonomic CLI. Many existing projects use it.

TypeScript
# npm-like workflow
npm init # scaffold package.json
npm install express # add runtime dep
npm install -D jest # add dev dep
npm run start # run script
npm run test # run tests
cat package-lock.json # exact lock file
Python
# Poetry — npm-like workflow for Python
poetry new my-project # scaffold pyproject.toml + src/
poetry add fastapi # add runtime dep
poetry add --group dev pytest # add dev dep
poetry run python main.py # run script
poetry run pytest # run tests
cat poetry.lock # exact lock file
pip + venvpoetryuv
Speedslowmediumvery fast
Lock filerequirements.txt (manual)poetry.lockuv.lock
pyproject.tomlpartialfullfull
Venv auto-managementmanualyesyes
Maturityvery stablestablenewer (2024+)
Recommendationlegacy projectsexisting poetry projectsnew projects

Playground note: Package managers modify the filesystem and network — they require a terminal. Run the commands above in your project directory.

What is the Python equivalent of npm's node_modules isolation per project?
Which command creates a virtual environment in a .venv directory?
What is the uv equivalent of "npm ci" — installing exactly from a lockfile?
Which modern file replaces requirements.txt as the project's dependency manifest?