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