Deployment

Running the Server

from neutron import App

app = App(title="My API", version="1.0.0")

# Development
app.run(host="127.0.0.1", port=8000)

# Production
app.run(host="0.0.0.0", port=8000, server="uvicorn", workers=4)

Server Backends

| Backend | Install | Features | |---------|---------|----------| | uvicorn (default) | Included | Asyncio, HTTP/1.1, WebSocket | | granian | pip install granian | Rust/Tokio, HTTP/2, faster |

# Use granian for better performance
app.run(server="granian", workers=4)

Configuration

Pydantic Settings with NEUTRON_ prefix:

| Variable | Default | Description | |----------|---------|-------------| | NEUTRON_HOST | 0.0.0.0 | Bind address | | NEUTRON_PORT | 8000 | Listen port | | NEUTRON_WORKERS | 1 | Worker processes | | NEUTRON_DEBUG | false | Debug mode | | NEUTRON_DATABASE_URL | — | Connection string (required) | | NEUTRON_DB_POOL_MIN | 5 | Min pool connections | | NEUTRON_DB_POOL_MAX | 25 | Max pool connections | | NEUTRON_LOG_LEVEL | info | Log level | | NEUTRON_LOG_FORMAT | json | Log format (json or pretty) |

Built-in Endpoints

Every app exposes:

| Endpoint | Description | |----------|-------------| | GET /health | {"status": "ok", "nucleus": true, "version": "1.0.0"} | | GET /openapi.json | OpenAPI 3.1 spec | | GET /docs | Swagger UI |

Lifespan Events

from contextlib import asynccontextmanager

@asynccontextmanager
async def lifespan(app):
    # Startup
    await db.connect()
    await cache.warmup()
    yield
    # Shutdown
    await cache.flush()
    await db.close()

app = App(lifespan=lifespan)

Docker

FROM python:3.12-slim

WORKDIR /app
COPY pyproject.toml .
RUN pip install --no-cache-dir .

COPY . .
EXPOSE 8000

CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"]

With granian (faster)

FROM python:3.12-slim

WORKDIR /app
COPY pyproject.toml .
RUN pip install --no-cache-dir ".[fast]"

COPY . .
EXPOSE 8000

CMD ["granian", "main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4", "--interface", "asgi"]

Docker Compose

services:
  app:
    build: .
    ports:
      - "8000:8000"
    environment:
      NEUTRON_DATABASE_URL: postgres://nucleus:5432/mydb
      NEUTRON_LOG_LEVEL: info
      NEUTRON_WORKERS: 4
    depends_on:
      nucleus:
        condition: service_healthy

  nucleus:
    image: ghcr.io/neutron-build/nucleus:latest
    ports:
      - "5432:5432"
    volumes:
      - nucleus_data:/var/lib/nucleus
    healthcheck:
      test: ["CMD", "pg_isready", "-h", "localhost"]
      interval: 5s

volumes:
  nucleus_data:

Dependencies

# pyproject.toml
[project]
dependencies = [
    "starlette>=0.38.0",
    "pydantic>=2.0",
    "uvicorn[standard]>=0.30.0",
    "asyncpg>=0.29.0",
    "structlog>=24.0.0",
]

[project.optional-dependencies]
fast = ["granian>=2.0.0"]
auth = ["PyJWT[crypto]>=2.8.0"]

systemd

[Unit]
Description=My Neutron Python App
After=network.target

[Service]
Type=simple
User=myapp
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/.venv/bin/python -m uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4
Environment=NEUTRON_DATABASE_URL=postgres://localhost:5432/mydb
Restart=on-failure
RestartSec=5
TimeoutStopSec=30

[Install]
WantedBy=multi-user.target