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.dbDEBUG=FalseAPP_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:
importstructloglog=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 -vUse
pytest-asynciofor async endpoints.Group tests under
src/app/tests/.Prefer
httpx.AsyncClientwithASGITransportfor integration tests:fromhttpximportAsyncClient, ASGITransportfromapp.mainimportapp@pytest.mark.asyncioasyncdeftest_health(): asyncwithAsyncClient(transport=ASGITransport(app=app), base_url="http://test") asac: res=awaitac.get("/health") assertres.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: CIon: [push, pull_request]jobs:
test:
runs-on: ubuntu-lateststeps:
- 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 |
