Python

How Anvil runs Django, FastAPI and Flask projects through uv, installs Python versions and picks one per project.

What Anvil detects

TypeDetected byStarted with
Djangomanage.py that imports Djangopython manage.py runserver 127.0.0.1:$PORT
FastAPIfastapi in pyproject.toml or requirements.txtuvicorn <module>:app --host 127.0.0.1 --port $PORT --reload
Flaskflask in pyproject.toml or requirements.txtflask run --host 127.0.0.1 --port $PORT --debug

With a package.json present, FastAPI and Flask count only if there is also a main.py, app.py, wsgi.py or app/main.py; otherwise it's a Node.js application. Python is checked before package.json, so Django with a frontend stays Django. PHP, Rust, Go and .NET are recognized first; see the detection table.

FastAPI's module is main (main.py), then app.main (app/main.py), then app (app.py). Flask finds app.py or wsgi.py itself.

Anvil starts the dev server on a private port passed in $PORT and proxies <name>.test to it.

Installing Python

Settings › Languages › Python › Install, or:

anvil runtime install python 3.13

Versions: 3.14, 3.13, 3.12, 3.11. The first install downloads a pinned uv release, checked against its SHA-256, into ~/.anvil/runtimes/uv. uv then installs the python-build-standalone build (checked against uv's built-in checksums) into ~/.anvil/runtimes/python.

Neither Anvil nor uv installs a Python by itself (uv runs with downloads set to manual), and uv uses only Pythons in ~/.anvil, never the system's.

Choosing the version

There is no default version.

  • Without a pin, uv chooses among Anvil's Pythons: the version .python-version names, else the newest requires-python allows, else the newest installed. requirements.txt-only projects still follow .python-version. If the requested version isn't installed, uv stops and the application's log shows e.g. No interpreter found for Python 3.11 in managed installations; install it in Settings › Languages › Python and start again. A .python-version that requires-python rules out also stops uv.
  • With a pin (anvil app runtime mysite 3.12, or Python version in the Settings tab), Anvil passes it as UV_PYTHON, overriding .python-version. Outside requires-python, uv stops with an error in the log. anvil app runtime mysite goes back to automatic.

Without a pin, the Overview and the Automatic entry show the .python-version version if installed, else the newest. Anvil doesn't read requires-python, so what uv runs can differ.

Running an application

The start command runs through uv run, which installs dependencies first:

The project hasCommand
pyproject.toml with a [project] tableuv run <command>
requirements.txtuv run --no-project --with-requirements requirements.txt <command>
neitheruv run --no-project --with <framework> <command>

FastAPI adds --with uvicorn. A pyproject.toml without a [project] table (only ruff, poetry, etc. settings) doesn't count as a uv project.

Start command and port: Start command and Port in Settings, or anvil app command / anvil app port (no value resets). The automatic port is derived from the name, in 41000–44999, moving up on collision. The dev server gets PORT, and HOST/HOSTNAME = 127.0.0.1.

The dev server doesn't start on its own: Start in the Dev tab, or anvil app start mysite while the desktop app is open (this also starts dev processes marked Dev start). To start it with Anvil, turn on Start with Anvil in Settings or run anvil app autostart mysite true (off by default; with the CLI alone, restart anvil start). It runs until stopped or Anvil quits; while stopped, <name>.test shows a "not running" page.

Django settings

The Overview shows the lines to add to settings.py once:

if DEBUG:  # Anvil
    ALLOWED_HOSTS += [".test", "localhost", "127.0.0.1"]
    SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")

Without them Django returns 400 for .test addresses and forms fail CSRF. .localhost passes the host check in debug, but forms still need the proxy line. Both apply only under DEBUG.

In your terminal

No python, pip or uv terminal command, and uv adds no Python links to a bin folder. Anvil's uv is ~/.anvil/runtimes/uv/uv; run it with the variables in Caches and files to use Anvil's Pythons and caches.

Caches and files

VariableValue
UV_PYTHON_INSTALL_DIR~/.anvil/runtimes/python
UV_CACHE_DIR~/.anvil/cache/uv
UV_PYTHON_CACHE_DIR~/.anvil/cache/uv-python
UV_TOOL_DIR, UV_TOOL_BIN_DIR~/.anvil/cache/uv-tools, ~/.anvil/cache/uv-tools/bin
UV_PROJECT_ENVIRONMENT~/.anvil/cache/uv-venvs/<name>
UV_MANAGED_PYTHON1
UV_PYTHON_DOWNLOADSmanual
UV_PYTHON_BIN_DIR~/.anvil/cache/uv-python-bin
UV_PYTHON_INSTALL_BIN0
UV_PYTHONThe pinned version, only when the application has a pin

An existing .venv is left alone. A pyproject.toml project gets a uv.lock; a requirements.txt-only project gets nothing added.

New applications

anvil new django site
anvil new fastapi api
anvil new flask web

Or New… (⌘N) in the app, under Python. Needs a Python installed.

TemplateWhat it creates
djangodjango-admin startproject with the settings package named config, the lines above appended to config/settings.py (with the domain suffix you use), and a requirements.txt with django
fastapimain.py with an app and a requirements.txt with fastapi and uvicorn
flaskapp.py with an app and a requirements.txt with flask

All templates take --git/--no-git and --https/--no-https; see New applications.

Differences from production

  • The framework's dev server runs: Django's runserver, uvicorn with --reload, Flask with --debug, on 127.0.0.1 only.
  • The environment is in ~/.anvil/cache/uv-venvs, not in the project.
  • Only Pythons installed through Anvil run, never the system's.

Removing a version

Hover the version in Settings › Languages › Python and click Uninstall, or anvil runtime uninstall python 3.12. uv removes it from ~/.anvil/runtimes/python.

Anvil refuses while applications are pinned to it ("api uses Python 3.12 — switch it to another version first"); Settings then shows Pinned by with their names instead of Uninstall. Unpin: set Python version to Automatic or another version, or run anvil app runtime api without a version (with only one version installed the field is disabled; use the command). A version only .python-version or requires-python asks for isn't a pin: the uninstall goes ahead, and the application fails to start with uv's error until it's reinstalled.

On this page