A powerful CLI tool to scaffold production-ready FastAPI projects with flexible database, auth, broker, and deployment options.
Project description
⚡ fastapi-spawn
The most complete FastAPI project scaffolding CLI — built for modern Python development.
Generate production-ready FastAPI projects in seconds — with exactly the stack you need.
Installation
pip install fastapi-spawn
# or
uv pip install fastapi-spawn
Quick Start
# Interactive TUI — guided step-by-step
fastapi-spawn new my-api
# Full stack one-liner
fastapi-spawn new my-api \
--db postgresql \
--orm sqlalchemy \
--migration alembic \
--auth jwt \
--broker redis \
--storage s3 \
--ai openai \
--monitoring sentry \
--email sendgrid \
--notify slack \
--log-lib loguru \
--log-dest local \
--vector-db qdrant \
--api-extra both \
--stack full \
--ci github
# Preview file tree without writing
fastapi-spawn new my-api --dry-run
# Add a feature to an existing project
fastapi-spawn add openai
fastapi-spawn add alembic
fastapi-spawn add sentry
---
## 🆘 Built-in Help & Auto-Suggestions
`fastapi-spawn` comes with an integrated global help menu and intelligent typo correction:
```bash
# Display the interactive global help menu
fastapi-spawn help
# Or use the standard flag
fastapi-spawn --help
Auto-Typo Correction (Did you mean?)
If you accidentally misspell a command, the CLI will catch it and suggest the right one automatically to save you time.
$ fastapi-spawn nw my_app
Error: No such command 'nw'. Did you mean 'new'?
Generated Project Structure
my-api/
├── app/
│ ├── api/
│ │ ├── graphql.py # Strawberry GraphQL schema + IDE (if graphql)
│ │ └── v1/
│ │ ├── router.py # Central API router aggregating sub-routers
│ │ ├── health/
│ │ │ └── router.py # GET /health /readiness /liveness
│ │ ├── auth/
│ │ │ └── router.py # POST /auth/login /auth/refresh (if auth)
│ │ └── ws/
│ │ └── router.py # WebSocket /ws/connect (if websockets)
│ ├── core/
│ │ ├── config.py # Pydantic Settings v2 — individual env fields + @property URLs
│ │ ├── logger.py # Context-var logger — request ID, client IP, file rotation
│ │ ├── exceptions.py # Custom exception hierarchy + handlers
│ │ ├── security.py # JWT / bcrypt
│ │ ├── ws_manager.py # WebSocket connection manager — broadcast, rooms
│ │ ├── storage.py # AWS S3/MinIO | GCS | Cloudinary
│ │ ├── ai.py # OpenAI | Anthropic | Gemini | Ollama | LangChain | LlamaIndex
│ │ ├── monitoring.py # Sentry | Prometheus | OpenTelemetry
│ │ ├── email.py # SendGrid | SMTP | AWS SES
│ │ ├── notifications.py # Slack | Discord webhooks
│ │ └── vector_db.py # Qdrant | ChromaDB | Pinecone | Supabase | Elasticsearch
│ ├── middleware/
│ │ ├── request_logger.py # X-Request-ID, response time, structured logs
│ │ └── rate_limit.py # slowapi — 200/min default, 429 + Retry-After
│ ├── db/
│ │ └── session.py # Async SQLAlchemy / SQLModel / Tortoise / Beanie
│ ├── models/
│ ├── schemas/
│ ├── services/
│ └── repositories/
├── tasks/
│ ├── celery_app.py # Celery (Redis / RabbitMQ)
│ ├── sample_tasks.py
│ └── arq_worker.py # Arq async task queue (if arq)
├── migrations/ # Alembic async
│ ├── env.py
│ └── versions/
├── infra/
│ ├── docker/
│ ├── helm/
│ └── terraform/
├── tests/
├── logs/ # Local rotating logs
├── main.py # uv run main.py
├── alembic.ini
├── Dockerfile
├── docker-compose.yml
├── Makefile
├── .env # gitignored
├── .env.example # full reference of every supported variable
├── .gitignore
├── .pre-commit-config.yaml
└── pyproject.toml # [tool.uv.scripts] pre-wired
All Options
fastapi-spawn new [OPTIONS] PROJECT_NAME
Database & ORM
--db postgresql | mysql | mongodb | sqlite | supabase | duckdb | none
--orm sqlalchemy | sqlmodel | tortoise | beanie | none
--migration alembic | aerich | none
Auth & Security
--auth jwt | oauth2 | api-key | auth0 | none
Messaging & Cache
--broker redis | rabbitmq | kafka | arq | none
--cache redis | memcached | none
Storage
--storage s3 | gcs | cloudinary | local | none
AI / LLM
--ai openai | anthropic | gemini | ollama | langchain | llamaindex | none
API Extras
--api-extra websockets | graphql | both | none
Monitoring
--monitoring sentry | prometheus | opentelemetry | both | none
Email
--email sendgrid | smtp | ses | none
Notifications
--notify slack | discord | none
Logging
--log-lib loguru | structlog | standard
--log-dest local | cloudwatch | datadog | none
Vector Database
--vector-db qdrant | chroma | pinecone | supabase | elasticsearch | none
Deployment
--stack minimal | standard | full
--ci github | gitlab | both | none
Flags
--no-docker Skip Docker files
--no-tests Skip test suite
--dry-run Preview file tree without writing
--force / -f Overwrite existing directory
--output / -o Output directory (default: .)
uv run Scripts
Every generated project has [tool.uv.scripts] pre-wired:
uv run dev # uvicorn --reload
uv run start # python main.py
uv run test # pytest --cov
uv run lint # ruff check
uv run format # ruff format
uv run typecheck # mypy
uv run migrate # alembic upgrade head (if alembic)
uv run rollback # alembic downgrade -1 (if alembic)
uv run makemig # alembic revision --autogenerate (if alembic)
uv run worker # celery worker (if celery)
uv run beat # celery beat (if celery)
Environment Variables
Individual fields per service — no URL strings. All connection URLs are assembled via @property in app/core/config.py. Your .env.example includes every supported variable:
# ── Application ──────────────────────────────────────────────────────────────
APP_NAME=my-api
ENVIRONMENT=dev # dev | staging | production
SECRET_KEY=CHANGE_ME # openssl rand -hex 32
CORS_ORIGINS=http://localhost:3000,http://localhost:8000
# ── Logging ───────────────────────────────────────────────────────────────────
LOG_LEVEL=INFO
LOG_DIR=logs
LOG_BACKUP_DAYS=30
# ── PostgreSQL ─────────────────────────────────────────────────────────────
POSTGRES_USER=postgres
POSTGRES_PASSWORD=CHANGE_ME
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_DB=my_api_db
# → assembled as: postgresql+asyncpg://USER:PASS@HOST:PORT/DB
# ── MySQL ─────────────────────────────────────────────────────────────────
MYSQL_USER=root
MYSQL_PASSWORD=CHANGE_ME
MYSQL_HOST=localhost
MYSQL_PORT=3306
MYSQL_DB=my_api_db
# → assembled as: mysql+aiomysql://USER:PASS@HOST:PORT/DB
# ── MongoDB ───────────────────────────────────────────────────────────────
MONGODB_USER=mongo
MONGODB_PASSWORD=CHANGE_ME
MONGODB_HOST=localhost
MONGODB_PORT=27017
MONGODB_DB=my_api_db
# → assembled as: mongodb://USER:PASS@HOST:PORT
# ── Supabase ──────────────────────────────────────────────────────────────
SUPABASE_URL=https://xxxx.supabase.co
SUPABASE_KEY=CHANGE_ME # anon or service role key
# ── DuckDB ────────────────────────────────────────────────────────────────
DUCKDB_FILE=my_api.duckdb
# ── Redis ─────────────────────────────────────────────────────────────────
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_DB=0
# → assembled as: redis://:PASS@HOST:PORT/DB
# ── RabbitMQ ─────────────────────────────────────────────────────────────
RABBITMQ_USER=guest
RABBITMQ_PASSWORD=CHANGE_ME
RABBITMQ_HOST=localhost
RABBITMQ_PORT=5672
RABBITMQ_VHOST=/
# → assembled as: amqp://USER:PASS@HOST:PORT/VHOST
# ── Kafka ────────────────────────────────────────────────────────────────
KAFKA_HOST=localhost
KAFKA_PORT=9092
# → assembled as: HOST:PORT
# ── Auth / JWT ───────────────────────────────────────────────────────────
ACCESS_TOKEN_EXPIRE_MINUTES=30
REFRESH_TOKEN_EXPIRE_DAYS=7
ALGORITHM=HS256
# ── Auth0 ────────────────────────────────────────────────────────────────
AUTH0_DOMAIN=your-tenant.auth0.com
AUTH0_CLIENT_ID=CHANGE_ME
AUTH0_CLIENT_SECRET=CHANGE_ME
AUTH0_AUDIENCE=https://your-api.example.com
# ── AWS (S3 / SES / CloudWatch) ──────────────────────────────────────────
AWS_ACCESS_KEY_ID=CHANGE_ME
AWS_SECRET_ACCESS_KEY=CHANGE_ME
AWS_REGION=us-east-1
AWS_S3_BUCKET=my-api-bucket
AWS_S3_ENDPOINT_URL= # http://localhost:9000 for MinIO
# ── Google Cloud Storage ─────────────────────────────────────────────────
GCS_PROJECT_ID=CHANGE_ME
GCS_BUCKET=my-api-bucket
GOOGLE_APPLICATION_CREDENTIALS=./service-account.json
# ── Cloudinary ───────────────────────────────────────────────────────────
CLOUDINARY_CLOUD_NAME=CHANGE_ME
CLOUDINARY_API_KEY=CHANGE_ME
CLOUDINARY_API_SECRET=CHANGE_ME
# ── OpenAI ───────────────────────────────────────────────────────────────
OPENAI_API_KEY=sk-placeholder
OPENAI_MODEL=gpt-4o
OPENAI_EMBEDDING_MODEL=text-embedding-3-small
OPENAI_BASE_URL= # blank = api.openai.com
# Azure: https://<resource>.openai.azure.com/
# LM Studio: http://localhost:1234/v1
# ── Anthropic ────────────────────────────────────────────────────────────
ANTHROPIC_API_KEY=sk-ant-placeholder
ANTHROPIC_MODEL=claude-3-5-sonnet-20241022
# ── Google Gemini ────────────────────────────────────────────────────────
GEMINI_API_KEY=CHANGE_ME
GEMINI_MODEL=gemini-1.5-pro
# ── Ollama (local LLM — no API key) ─────────────────────────────────────
OLLAMA_HOST=localhost
OLLAMA_PORT=11434
OLLAMA_MODEL=llama3
# → assembled as: http://HOST:PORT
# ── Sentry ───────────────────────────────────────────────────────────────
SENTRY_DSN=https://xxx@sentry.io/yyy
# ── Datadog ──────────────────────────────────────────────────────────────
DD_API_KEY=CHANGE_ME
DD_SITE=datadoghq.com
# ── SendGrid ─────────────────────────────────────────────────────────────
SENDGRID_API_KEY=SG.placeholder
SENDGRID_FROM_EMAIL=noreply@example.com
# ── SMTP ─────────────────────────────────────────────────────────────────
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=CHANGE_ME
SMTP_PASSWORD=CHANGE_ME
SMTP_FROM_EMAIL=noreply@example.com
SMTP_STARTTLS=true
SMTP_SSL=false
# ── AWS SES ──────────────────────────────────────────────────────────────
SES_FROM_EMAIL=noreply@example.com # uses AWS_* credentials above
# ── Resend ───────────────────────────────────────────────────────────────
RESEND_API_KEY=re_placeholder
RESEND_FROM_EMAIL=noreply@example.com
# ── Slack ────────────────────────────────────────────────────────────────
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/CHANGE_ME
# ── Discord ──────────────────────────────────────────────────────────────
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/CHANGE_ME
# ── Qdrant ───────────────────────────────────────────────────────────────
QDRANT_HOST=localhost
QDRANT_PORT=6333
QDRANT_API_KEY= # blank for local Docker Qdrant
# → assembled as: http://HOST:PORT
# ── Pinecone ─────────────────────────────────────────────────────────────
PINECONE_API_KEY=CHANGE_ME
PINECONE_INDEX_NAME=my-api-index
# ── Elasticsearch ────────────────────────────────────────────────────────
ELASTICSEARCH_HOST=localhost
ELASTICSEARCH_PORT=9200
ELASTICSEARCH_API_KEY=
# → assembled as: http://HOST:PORT
# ── OpenSearch ───────────────────────────────────────────────────────────
OPENSEARCH_HOST=localhost
OPENSEARCH_PORT=9200
OPENSEARCH_USER=admin
OPENSEARCH_PASSWORD=admin
# ── Vespa ────────────────────────────────────────────────────────────────
VESPA_ENDPOINT=http://localhost:8080
# ── Extras (Stripe, SSO, Meilisearch) ────────────────────────────────────
STRIPE_API_KEY=sk_test_placeholder
STRIPE_WEBHOOK_SECRET=whsec_placeholder
GOOGLE_CLIENT_ID=placeholder
GOOGLE_CLIENT_SECRET=placeholder
GITHUB_CLIENT_ID=placeholder
GITHUB_CLIENT_SECRET=placeholder
MICROSOFT_CLIENT_ID=placeholder
MICROSOFT_CLIENT_SECRET=placeholder
MEILISEARCH_HOST=http://localhost:7700
MEILISEARCH_API_KEY=masterKey
All variables are assembled into connection URLs inside
app/core/config.pyvia@property. Your code always reads from structured fields — never a fragile connection string.
Middleware (always included)
| Middleware | Behaviour |
|---|---|
RequestLoggingMiddleware |
Assigns X-Request-ID, logs → METHOD /path + ✓ status Xms with client IP |
RateLimitMiddleware |
200 req/min default via slowapi, returns 429 + Retry-After: 60 |
CORSMiddleware |
Configurable origins via CORS_ORIGINS env var |
Every response carries X-Request-ID and X-Response-Time headers automatically.
WebSockets
# Connect: ws://host/api/v1/ws/connect
# Room: ws://host/api/v1/ws/connect/{room_id}
# Client protocol
{"type": "broadcast", "data": "hello everyone"}
{"type": "ping"} # → {"type": "pong"}
GraphQL
Strawberry schema with Query + Mutation + Subscription is mounted at /graphql.
GraphiQL IDE is enabled in dev mode. Subscriptions use graphql-transport-ws.
🧩 Add Features to Existing Projects (Incremental Scaffolding)
Did you generate a minimal project and now realize you need WebSockets, AWS S3, or OpenAI? No problem.
fastapi-spawn add allows you to incrementally scale your project. Instead of re-generating your entire project or copying boilerplate manually, you can inject production-ready modules into your existing codebase.
fastapi-spawn add [FEATURE]
Or you can add them at creation time with the --extra flag:
fastapi-spawn new my_app --extra stripe --extra sso --extra seed
All Possibilities you can add or --extra:
You can run any of the following commands inside an existing project:
# Infrastructure & Deployment
fastapi-spawn add docker # Dockerfile and docker-compose.yml
fastapi-spawn add helm # Helm chart in infra/helm/
fastapi-spawn add terraform # Terraform in infra/terraform/
fastapi-spawn add github-actions # CI/CD pipeline (.github/workflows/tests.yml)
# AI & Vector DBs
fastapi-spawn add openai # OpenAI async client
fastapi-spawn add anthropic # Anthropic Claude async client
fastapi-spawn add gemini # Google Generative AI client
fastapi-spawn add qdrant # Qdrant vector DB
fastapi-spawn add chroma # ChromaDB local vector DB
fastapi-spawn add pinecone # Pinecone cloud vector DB
fastapi-spawn add meilisearch # Meilisearch typo-tolerant search
fastapi-spawn add opensearch # OpenSearch vector & text search
fastapi-spawn add vespa # Vespa big data serving engine
fastapi-spawn add ocr # PDF & OCR data extraction pipeline
# Payments & Identity
fastapi-spawn add stripe # Stripe payments & webhooks
fastapi-spawn add sso # FastAPI SSO (Google, GitHub, Microsoft)
fastapi-spawn add sso-google # FastAPI SSO (Google only)
fastapi-spawn add sso-github # FastAPI SSO (GitHub only)
fastapi-spawn add sso-microsoft # FastAPI SSO (Microsoft only)
# Messaging & Async Workers
fastapi-spawn add celery # Celery worker + tasks/
fastapi-spawn add arq # Arq async job queues using Redis
fastapi-spawn add websockets # WebSocket connection manager
fastapi-spawn add sse # Server-Sent Events streaming
# Storage, APIs, Seeding & Monitoring
fastapi-spawn add s3 # AWS S3 / MinIO storage
fastapi-spawn add graphql # Strawberry GraphQL schema
fastapi-spawn add alembic # Alembic async migrations
fastapi-spawn add seed # Faker database seeding script (Users, Posts, Comments)
fastapi-spawn add resend # Resend modern email client
fastapi-spawn add sentry # Sentry APM integration
fastapi-spawn add prometheus # Prometheus metrics
# Advanced API Features
fastapi-spawn add rbac # Role-Based Access Control (@RequireRole decorator)
fastapi-spawn add caching # Redis API Response Caching (@cache decorator)
fastapi-spawn add response-format # Global formatted JSON response middleware
fastapi-spawn add admin # Internal CRUD Admin Dashboard (sqladmin)
fastapi-spawn add pagination # Automatic endpoint pagination logic
fastapi-spawn add uploads # File upload router (Multipart Form)
Example:
$ fastapi-spawn add websockets
✓ Created app/core/ws_manager.py
✓ Created app/api/v1/ws/router.py
👉 Next Steps:
1. Mount the router in app/api/v1/router.py:
from app.api.v1.ws.router import router as ws_router
router.include_router(ws_router)
ORM ↔ Database Compatibility
| ORM | Compatible Databases |
|---|---|
sqlalchemy |
postgresql, mysql, sqlite, supabase |
sqlmodel |
postgresql, mysql, sqlite, supabase |
tortoise |
postgresql, mysql, sqlite |
beanie |
mongodb |
none |
any |
Contributing
git clone https://github.com/Bishwajitgarai/fastapi-spawn
cd fastapi-spawn
uv sync --all-extras
uv run pytest
License
MIT © Bishwajit Garai
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fastapi_spawn-0.4.17.tar.gz.
File metadata
- Download URL: fastapi_spawn-0.4.17.tar.gz
- Upload date:
- Size: 63.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1bd97bf6a214c1ec53ca95adcc0c35767efa3ec0ad11014bfe1af8989a9c7300
|
|
| MD5 |
3f2029771a10bc65cb0e9ac508acece9
|
|
| BLAKE2b-256 |
a2d12c42360d70bc7a28c2865f8d1a39f0cc5d556a1b76d0099f8063ebd64447
|
File details
Details for the file fastapi_spawn-0.4.17-py3-none-any.whl.
File metadata
- Download URL: fastapi_spawn-0.4.17-py3-none-any.whl
- Upload date:
- Size: 89.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a462555c0b2c9fa60ccfb0cfd05a410934eaf34852f469ea3c94a9512b8b9d00
|
|
| MD5 |
45e8bd99e72c5fc39220ab59a7b71749
|
|
| BLAKE2b-256 |
b5d3dc11d3cc5f49be8f3eca6167cb190408a23a61836810dc1341b62a779639
|