Migrate from requirements.txt to pyproject.toml: 5-Step Process for Flask Applications
Python projects traditionally managed dependencies with pip install -r requirements.txt. While straightforward, requirements.txt files lack lockfiles, leading to inconsistent installs across environments. Modern pyproject.toml (PEP 518/621) with tools like Poetry provides declarative dependencies, lockfiles (poetry.lock), and reproducible builds—particularly suitable for Flask web apps in production.
We’ll follow this 5-step process to migrate a Flask project, as tested with Python 3.12 and Flask 3.0.
Why Migrate for Flask Apps?
- Reproducibility:
poetry.lockpins exact versions, preventing “works on my machine” issues. - Speed: Typically faster
poetry installthanpip install -r requirements.txt. - Standards: Aligns with Python’s future; supports scripts, plugins, build reqs.
- Flask Benefits: Handles dev/prod deps (e.g.,
flask[async]), Gunicorn, etc.
Choosing Your Dependency Tool
Poetry excels with lockfiles and simple syntax, but consider these alternatives:
- pip-tools:
pip-compile requirements.in→ lockedrequirements.txt. Pip-native, minimal overhead. - PDM: Fast, PEP 621 native, lockfiles, scripts support.
- uv: Ultra-fast from Astral, growing pyproject.toml integration.
Poetry suits many Flask projects due to extras and workspace support, though select based on your needs.
Prerequisites
- Python 3.11+
- Existing Flask app with
requirements.txt - Backup your project
Step 1: Install Poetry
$ curl -sSL https://install.python-poetry.org | python3 -
# Example output (abbreviated):
Retrieving Poetry metadata
...
Poetry (version 1.8.3) successfully installed.
$ poetry --version
Poetry (version 1.8.3)
# If not found, add export PATH=\"$HOME/.local/bin:\$PATH\" to ~/.bashrc or ~/.zshrc, then source it.
Step 2: Initialize Poetry in Your Flask Project
$ cd /path/to/your/flask-app
$ poetry init --no-interaction # Skips interactive prompts; outputs basic pyproject.toml
This creates basic pyproject.toml. Edit to set:
[tool.poetry]
name = "my-flask-app"
version = "0.1.0"
description = "Flask web application"
authors = ["Your Name <email@example.com>"]
packages = [{include = "app"}] # Adjust to your src layout
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
Step 3: Import Dependencies from requirements.txt
# Add all from requirements.txt (Poetry parses pins)
$ xargs poetry add < requirements.txt
# Note: Assumes simple lines without comments or extras; manual add for complex cases.
# Example requirements.txt:
# flask==3.0.0
# gunicorn>=21.0.0
#
# Runs: poetry add flask==3.0.0 gunicorn>=21.0.0
Review pyproject.toml:
[tool.poetry.dependencies]
python = "^3.12"
flask = "^3.0.0"
gunicorn = ">=21.0"
Separate dev deps:
$ poetry add --group dev pytest black
Step 4: Generate Lockfile and Test Flask App
$ poetry lock # Generates poetry.lock with resolved deps
$ poetry install # Installs to project venv
# Test Flask
poetry run flask run
# Or: poetry run gunicorn app:app
Verify imports and app:
$ poetry run python -c "import flask; print('Flask:', flask.__version__)"
Flask: 3.0.0
$ poetry run python -c "import gunicorn; print('Gunicorn OK')"
Gunicorn OK
App starts with $ poetry run flask run; test endpoints.
Step 5: Update Scripts, CI/CD, and Cleanup
- Update
run.shor Makefile:poetry run flask run - Docker:
poetry export -f requirements.txt --output requirements.txtfor prod if needed. - GitHub Actions:
- name: Install Poetry uses: snok/install-poetry@master - run: poetry install --no-dev - Remove
requirements.txt:git rm requirements.txt - Commit:
git add pyproject.toml poetry.lock
Troubleshooting Common Issues
| Issue | Fix |
|---|---|
| Version conflicts | poetry lock --no-update |
| Extras (e.g., flask[async]) | poetry add 'flask[async]' |
| Editable installs | poetry add -e . |
| Monorepo workspaces | [tool.poetry.group.workspace.dependencies] |
| Slow resolution | poetry lock --no-update; update Poetry |
| Binary deps fail (e.g. cryptography) | Install system build deps (gcc, etc.) or use Docker |
| requirements.txt comments | Strip comments or add deps manually |
| Git/URL deps | poetry add git+https://...@v1.0 |
Verify Migration
$ poetry show --tree # Dependency tree
$ poetry check # Validate pyproject.toml
# Example: ✓ pyproject.toml is valid
Conclusion
With this migration, your Flask app now uses pyproject.toml and poetry.lock for reproducible deployments. Next, consider adding [tool.poetry.scripts] for tasks like poetry run test.
Related:
Share your migration experience below!
Sponsored by Durable Programming
Need help maintaining or upgrading your Python application? Durable Programming specializes in keeping Python apps secure, performant, and up-to-date.
Hire Durable Programming