GuidesLanguage guides
Python
Ferry builds a Python app from requirements.txt, pyproject.toml or Pipfile.
Detect. Ferry finds requirements.txt, pyproject.toml or Pipfile.
1 / 5
A minimal example
app.py
requirements.txt
Procfile
flask==3.1.*
gunicorn==23.*from flask import Flask
app = Flask(__name__)
@app.get("/")
def hello():
return "Hello from Python on Ferry\n"web: gunicorn app:app --bind 0.0.0.0:$PORTferry up hello-python --followThe Procfile line runs with sh -c. Thus the shell replaces $PORT with the value. For FastAPI, use web: uvicorn main:app --host 0.0.0.0 --port $PORT.
What Ferry generates
| Step | What Ferry generates |
|---|---|
| Base image | python:<version>-slim. The default is 3.12. Ferry uses the major.minor of .python-version or runtime.txt (python-3.11.9), if there is one. Ferry sets PYTHONUNBUFFERED=1. Thus the logs show immediately. |
| Build | Your build command, if you set one. Example: python manage.py collectstatic --noinput. |
| Start | python main.py or python app.py, when the file exists. All other servers (Gunicorn, Uvicorn, Django) need a Procfile entry or --start-cmd. |
The install command
| Ferry finds | Install |
|---|---|
requirements.txt | pip install -r requirements.txt |
uv.lock | the locked dependencies, with uv |
poetry.lock or [tool.poetry] | poetry install --only main |
a packaged pyproject.toml | pip install . |
a plain PEP 621 pyproject.toml | its [project] dependencies |
Pipfile | pipenv install --system --deploy (--skip-lock with no Pipfile.lock) |
System packages
Ferry adds system packages when your dependencies need them. The -binary variants need nothing.
| Dependency | Packages |
|---|---|
psycopg2 or psycopg[c] | build-essential libpq-dev |
psycopg | libpq5 |
mysqlclient | build-essential default-libmysqlclient-dev pkg-config |