# Python

Python is supported out of the box with Specific. This guide covers running Python services with virtual environments, module resolution, and common frameworks.

## Basic configuration

Use `base = "python"` for builds. For development, point the dev command at your virtual environment's Python binary:

```hcl
build "api" {
  base = "python"
}

service "api" {
  build = build.api
  command = "python app.py"

  endpoint {
    public = true
  }

  env = {
    PORT = port
    DATABASE_URL = postgres.main.url
  }

  dev {
    command = ".venv/bin/python app.py"
  }
}

postgres "main" {}
```

In production, `base = "python"` handles dependency installation automatically (see [Builds](/builds) for details). In development, you manage your own virtual environment.

## Virtual environments

Create a virtual environment in your project before running `specific dev`:

```sh
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
```

Or with `uv`:

```sh
uv venv .venv
uv pip install -r requirements.txt
```

There are two ways to reference the venv in your dev command:

**Direct path (recommended):**

```hcl
dev {
  command = ".venv/bin/python app.py"
}
```

**Shell activation:**

```hcl
dev {
  command = "source .venv/bin/activate && python app.py"
}
```

Both work because service commands run in a shell. The direct path is simpler and avoids potential issues with shell activation scripts.

## Module resolution

Python module imports work naturally because `specific dev` sets the working directory to the service's `root` (or the project root if no `root` is set). Standard imports resolve as expected:

```
myproject/
  specific.hcl
  app.py
  myapp/
    __init__.py
    utils.py
```

```python
# app.py
from myapp.utils import get_greeting  # works
```

You can also use `python -m` to run modules:

```hcl
dev {
  command = ".venv/bin/python -m myapp"
}
```

## Monorepo support

For monorepos, use `root` to set the working directory. The venv path is relative to `root`:

```hcl
build "api" {
  base = "python"
  root = "backend"
}

service "api" {
  build = build.api
  command = "python app.py"

  endpoint {
    public = true
  }

  env = {
    PORT = port
  }

  dev {
    command = ".venv/bin/python app.py"
  }
}
```

Here `.venv/bin/python` resolves to `backend/.venv/bin/python`.

## Common frameworks

### Flask

```hcl
build "api" {
  base = "python"
}

service "api" {
  build = build.api
  command = "flask run --host 0.0.0.0 --port $PORT"

  endpoint {
    public = true
  }

  env = {
    PORT = port
    FLASK_APP = "app"
  }

  dev {
    command = ".venv/bin/flask run --host 0.0.0.0 --port $PORT --reload"
  }
}
```

### FastAPI with uvicorn

```hcl
build "api" {
  base = "python"
}

service "api" {
  build = build.api
  command = "uvicorn app:app --host 0.0.0.0 --port $PORT"

  endpoint {
    public = true
  }

  env = {
    PORT = port
  }

  dev {
    command = ".venv/bin/uvicorn app:app --host 0.0.0.0 --port $PORT --reload"
  }
}
```

### Django

```hcl
build "web" {
  base = "python"
}

service "web" {
  build = build.web
  command = "gunicorn myproject.wsgi --bind 0.0.0.0:$PORT"

  endpoint {
    public = true
  }

  env = {
    PORT = port
    DATABASE_URL = postgres.main.url
  }

  pre_deploy {
    command = "python manage.py migrate"
  }

  dev {
    command = ".venv/bin/python manage.py runserver 0.0.0.0:$PORT"
  }
}

postgres "main" {}
```

## Database migrations

Use `pre_deploy` hooks for production migrations and `specific exec` for development:

```sh
specific exec api -- .venv/bin/python manage.py migrate
```
