Pyforge is a modern FastAPI backend starter template designed for production-grade Python 3.14+ development. It's built with clean architecture, async-first design, and developer experience in mind β featuring uv, Ruff, SQLAlchemy 2.0, Pydantic v2, and structured logging out of the box.
β Modern Stack
- Python 3.14 +
uvfor reproducible, lightning-fast dependency management - Async-first FastAPI + Uvicorn for high performance
- SQLAlchemy 2.0 async ORM with Alembic migrations
- Pydantic v2 and
pydantic-settingsfor configuration - Ruff for linting, formatting, and static type checks
- pytest + httpx for async testing
- structlog for production-ready structured logging
- Docker for containerization
- GitHub Actions CI for automatic quality checks
β Clean Architecture
src/app/
βββ api/ # Routes + dependency wiring
βββ core/ # Config, logging, security, rate limiting
βββ db/ # DB engine, sessions, migrations
βββ models/ # ORM entities
βββ schemas/ # Pydantic models
βββ services/ # Business logic
βββ exceptions/ # Custom errors & handlers
βββ tests/ # Unit and integration tests
uv replaces pip, virtualenv, and poetry with one fast tool.
Follow official installation:
curl -LsSf https://astral.sh/uv/install.sh | shgit clone https://github.com/helioLJ/pyforge.git
cd pyforge
uv syncπ‘ Recommendation: Always pin Python to 3.14+ in your
.tool-versionsorpyproject.tomlfor consistency.
# Option 1: Using FastAPI CLI (simpler)
uv run fastapi run src/app/main.py --reload
# Option 2: Using uvicorn directly (more control)
PYTHONPATH=src uv run uvicorn app.main:app --reloadYour API will be live at: π http://localhost:8000/docs
All configuration is handled through pydantic-settings.
DATABASE_URL=sqlite+aiosqlite:///./pyforge.db
DEBUG=False
APP_NAME=Pyforge- Never hardcode secrets in code; always use
.envor secret managers. - Use
model_config = SettingsConfigDict(env_file=".env")to load automatically. - For multiple environments, use
.env.development,.env.staging,.env.production.
Pyforge uses structlog for JSON-formatted structured logging, ideal for observability platforms like Grafana or Datadog.
- Use contextual loggers (
structlog.get_logger().bind(request_id=...)). - Keep logs structured, not human-formatted.
- Use
INFOin production andDEBUGin development. - Avoid
print()entirely β always log.
Example:
import structlog
log = structlog.get_logger()
log.info("user.created", user_id=123, email="john@example.com")| Layer | Purpose | Example Folder |
|---|---|---|
| Domain | Entities / Models | app/models |
| Application | Business logic | app/services |
| Infrastructure | Database, logging, config | app/core, app/db |
| Interface | API endpoints | app/api |
β
Keep dependencies inward only β outer layers depend on inner ones.
β
Avoid circular imports by organizing feature modules clearly.
β
Each domain (e.g. users, todos) should have its own schema, service, and router file.
uv run pytest -v-
Use
pytest-asynciofor async endpoints. -
Group tests under
src/app/tests/. -
Prefer
httpx.AsyncClientwithASGITransportfor integration tests:from httpx import AsyncClient, ASGITransport from app.main import app @pytest.mark.asyncio async def test_health(): async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as ac: res = await ac.get("/health") assert res.status_code == 200
-
Always test both happy-path and error scenarios.
-
Use fixtures for database sessions and mock data.
Run checks and formatting:
uv run ruff check .
uv run ruff format .- Stick to 100-char lines (
line-length = 100). - Let Ruff handle formatting automatically.
- Run Ruff before committing (
pre-commitconfigured). - Use type annotations everywhere; Ruff's type rules (
--select TYP) ensure type safety.
Set up once:
pre-commit installHooks included:
- Ruff linting & formatting
- Pyupgrade (ensures Python 3.14 syntax)
Run manually:
pre-commit run --all-filesuv run alembic init src/app/db/migrationsuv run alembic revision --autogenerate -m "create users table"uv run alembic upgrade head- Always commit migrations with code changes.
- Avoid editing Alembic scripts manually unless absolutely necessary.
- Use descriptive revision messages.
Pyforge ships with GitHub Actions configured for:
- β
Linting (
ruff check) - β
Type checks (
ruff check --select TYP) - β
Testing (
pytest) - β
Packaging (
uv build)
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v3
- run: uv sync
- run: uv run ruff check .
- run: uv run pytest -q- Keep CI fast: don't rebuild Docker here unless required.
- Extend with deploy stage only in private/prod repos.
- Store secrets in GitHub Encrypted Secrets, never in
.env.
docker compose up --build- Use multi-stage builds for smaller images.
- Base image:
python:3.14-slim. - Always set
PYTHONUNBUFFERED=1for real-time logs. - Use
uvinside Docker for consistent deps. - Expose port
8000(FastAPI default).
-
Create your feature branch
git checkout -b feat/add-auth
-
Run app
uv run fastapi run src/app/main.py --reload
-
Test before commit
uv run pytest pre-commit run --all-files
-
Push and PR GitHub Actions will validate code automatically.
Pyforge is intentionally modular. You can easily extend or replace components:
| Component | Default | Alternative Options |
|---|---|---|
| CI/CD | GitHub Actions | GitLab CI, CircleCI |
| ORM | SQLAlchemy | Tortoise ORM, GINO |
| Logger | structlog | Loguru (simpler dev) |
| Auth | JWT via FastAPI | OAuth2, Firebase |
| Config | pydantic-settings | Dynaconf, Environs |
| Deployment | Docker | Pulumi, ECS, Cloud Run |
- Always use async DB clients to avoid blocking the event loop.
- Avoid
time.sleep()β useawait asyncio.sleep(). - Keep endpoints slim β delegate logic to
services/. - Validate everything in Pydantic models, not route logic.
- Use dependency injection (
Depends) for shared logic (DB, rate limiters, auth). - Configure structured logs and metrics early β it's harder later.
- Follow semantic versioning for template updates.
MIT License Β© 2025 [helioLJ]
You're free to fork, modify, and use Pyforge in commercial or open-source projects. Just keep the license notice and share improvements if you can π‘
Contributions welcome!
- Fork the repo
- Create a feature branch (
feat/something) - Follow the code style (
uv run ruff format .) - Add tests for new features
- Submit a PR
For large contributions, open an issue first to discuss design direction.
| Category | Tool | Notes |
|---|---|---|
| Package Mgmt | uv |
Fast, reproducible, modern |
| Framework | FastAPI |
Async, type-safe web framework |
| ORM | SQLAlchemy |
Async ORM with migrations |
| Validation | Pydantic v2 |
Type-driven schemas |
| Logging | structlog |
JSON structured logging |
| Lint/Format | Ruff |
Unified code quality tool |
| Testing | pytest, httpx |
Async testing |
| CI/CD | GitHub Actions | Optional, modular |
| Deployment | Docker | Production ready |
