fastapi-project-generator

Generate complete FastAPI project skeleton with SQLAlchemy, MongoDB, JWT auth, Redis cache, Celery tasks, Docker, and CRUD generators. Use when user wants to create or scaffold a FastAPI project.

16 stars

Best use case

fastapi-project-generator is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Generate complete FastAPI project skeleton with SQLAlchemy, MongoDB, JWT auth, Redis cache, Celery tasks, Docker, and CRUD generators. Use when user wants to create or scaffold a FastAPI project.

Teams using fastapi-project-generator should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/fastapi-project-generator/SKILL.md --create-dirs "https://raw.githubusercontent.com/diegosouzapw/awesome-omni-skill/main/skills/backend/fastapi-project-generator/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/fastapi-project-generator/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How fastapi-project-generator Compares

Feature / Agentfastapi-project-generatorStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Generate complete FastAPI project skeleton with SQLAlchemy, MongoDB, JWT auth, Redis cache, Celery tasks, Docker, and CRUD generators. Use when user wants to create or scaffold a FastAPI project.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

This skill guides the creation of a production-ready FastAPI project with all necessary components.

## Project Structure

Generate this standardized structure:

```
project/
├── app/
│   ├── api/                    # API modules
│   │   ├── router.py           # Central route registration
│   │   └── [module]/           # Feature module (e.g., user, form)
│   │       ├── __init__.py
│   │       ├── models.py       # SQLAlchemy models
│   │       ├── schemas.py      # Pydantic schemas
│   │       ├── router.py       # APIRouter definitions
│   │       ├── views.py        # View functions
│   │       └── tasks.py        # Celery tasks
│   ├── core/                   # Core components
│   │   ├── __init__.py
│   │   ├── exceptions.py       # Custom exception handlers
│   │   ├── middleware.py       # CORS, compression, rate limiting
│   │   └── oauth2.py           # JWT authentication
│   ├── extensions/             # Extensions layer
│   │   ├── __init__.py
│   │   ├── db.py               # SQLAlchemy sync/async engines
│   │   ├── cache.py            # Redis client
│   │   └── mongo.py            # MongoDB Motor client
│   ├── settings/               # Configuration management
│   │   ├── __init__.py         # Settings loader
│   │   ├── development.py      # Development config
│   │   ├── testing.py          # Testing config
│   │   └── production.py       # Production config
│   ├── utils/                  # Utilities
│   │   ├── __init__.py
│   │   ├── logger.py           # Logging setup
│   │   └── helpers.py          # Helper functions
├── common/                     # Shared modules
│   ├── response.py             # Response wrappers (response_ok/response_err)
│   ├── security.py             # Password hashing, JWT
│   ├── pagination.py           # Custom pagination
│   └── error.py                # Custom exceptions
├── tests/                      # Test suite
├── alembic/                    # Database migrations
│   ├── versions/
│   └── env.py
├── docker/                     # Docker configuration
│   ├── Dockerfile
│   └── docker-compose.yml
├── requirements.txt            # Python dependencies
├── main.py                     # Application entry point (root directory)
├── .env                        # Environment variables
├── .env.example                # Environment template
├── .gitignore
└── alembic.ini
```

## Core Dependencies

Use these versions as baseline:

```txt
# Core
fastapi>=0.115.0
uvicorn[standard]>=0.30.0
pydantic>=2.5.0
pydantic-settings>=2.1.0

# Database
sqlalchemy>=2.0.25
alembic>=1.13.0
asyncmy>=0.2.10  # Async MySQL driver
redis>=5.0.1
motor>=3.3.0     # MongoDB async

# Auth
PyJWT>=2.10.0
pwdlib[argon2]>=0.3.0

# Rate limiting
slowapi>=0.1.9

# Tasks
celery>=5.3.0
redis>=5.0.1

# Utilities
python-multipart>=0.0.6
python-dotenv>=1.0.0
loguru>=0.7.0
httpx>=0.26.0
limits>=5.6.0
```

## Configuration Management

Use multi-environment settings based on `ENV` variable:

```python
# app/settings/__init__.py
import os
from typing import Dict
from functools import lru_cache
from dotenv import load_dotenv
load_dotenv('.env')

from app.settings.development import DevelopmentSettings
from app.settings.testing import TestingSettings
from app.settings.production import ProductionSettings


@lru_cache()
def get_settings():
    env = os.getenv('ENV', None)
    env_config: Dict = {
        "development": DevelopmentSettings(),
        "testing": TestingSettings(),
        "production": ProductionSettings()
    }
    if env is None or env not in env_config:
        raise EnvironmentError("ENV is undefined!")
    return env_config[env]


settings = get_settings()
```

```python
# app/settings/development.py
from pydantic import Field
from typing import List


class DevelopmentSettings:
    # App
    PROJECT_NAME: str = "FastAPI Project"
    VERSION: str = "1.0.0"
    ENVIRONMENT: str = "development"

    # Database
    SQLALCHEMY_DATABASE_ASYNC_URL: str = "mysql+asyncmy://user:pass@localhost:3306/db"
    SQLALCHEMY_DATABASE_SYNC_URL: str = "mysql+pymysql://user:pass@localhost:3306/db"
    SQLALCHEMY_POOL_SIZE: int = 5
    SQLALCHEMY_POOL_RECYCLE: int = 3600
    SQLALCHEMY_POOL_PRE_PING: bool = True
    SQLALCHEMY_ECHO: bool = False

    # Redis
    REDIS_URL: str = "redis://localhost:6379/0"

    # JWT
    JWT_SECRET_KEY: str = "your-secret-key"
    ALGORITHM: str = "HS256"
    ACCESS_TOKEN_EXPIRE_MINUTES: int = 30
    REFRESH_TOKEN_EXPIRE_DAYS: int = 7

    # MongoDB
    MONGODB_URL: str = "mongodb://localhost:27017"
    MONGODB_DB: str = "app"

    # Celery
    CELERY_BROKER_URL: str = "redis://localhost:6379/1"
    CELERY_RESULT_URL: str = "redis://localhost:6379/2"

    # CORS
    BACKEND_CORS_ORIGINS: List[str] = ["http://localhost:3000"]

    # Swagger
    SWAGGER_DOCS_URL: str = "/docs"
    SWAGGER_REDOC_URL: str = "/redoc"
    OPENAPI_URL: str = "/openapi.json"
```

## Response Wrapper

Use unified response format:

```python
# common/response.py
from typing import Union, List, Dict, Tuple, Optional
from starlette import status
from pydantic.types import JsonValue
from fastapi.responses import JSONResponse


class ErrCode(object):
    """Error codes"""
    # Common
    SYSTEM_ERROR = (1000, 'System error')
    QUERY_NOT_EXISTS = (1001, "Data not exists")
    QUERY_HAS_EXISTS = (1002, "Data already exists")
    COMMON_INTERNAL_ERR = (1004, 'Server error')
    COMMON_PERMISSION_ERR = (1005, 'No access permission')
    REQUEST_PARAMS_ERROR = (1006, "Request params error")
    DB_INTEGRITY_ERROR = (1007, 'Data conflict')
    DB_CONNECTION_ERROR = (1008, 'DB connection failed')
    TOO_MANY_REQUEST = (1009, "Too many requests")

    # Auth
    USER_NOT_EXISTS = (2000, 'User not exists')
    USER_HAS_EXISTS = (2001, 'User already exists')
    USER_NOT_ACTIVE = (2002, 'User not active')
    UNAME_OR_PWD_ERROR = (2003, "Username or password error")
    TOKEN_INVALID_ERROR = (2004, 'Token error')
    TOKEN_EXPIRED_ERROR = (2005, 'Token expired')


def response_ok(
    data: Optional[JsonValue] = None,
    msg: str = 'success',
    status_code = status.HTTP_200_OK,
    **kwargs
) -> JSONResponse:
    """Success response"""
    ret = {'errcode': 0, 'errmsg': msg}
    if data is not None:
        ret['data'] = data
    ret.update({k: v for k, v in kwargs.items() if k not in ret})
    return JSONResponse(ret, status_code=status_code)


def response_err(
    errcode: Tuple[int, str],
    errmsg: Optional[str] = None,
    detail: Union[List, Dict, None] = None,
    status_code = status.HTTP_200_OK
) -> JSONResponse:
    """Error response"""
    ret = {"errcode": errcode[0], "errmsg": errcode[1]}
    if errmsg is not None:
        ret['errmsg'] = errmsg
    if detail is not None:
        ret['detail'] = detail
    return JSONResponse(ret, status_code=status_code)
```

## Custom Pagination

```python
# common/pagination.py
from typing import Any, Optional
from fastapi import Query
from pydantic import BaseModel


class PageNumberPagination(BaseModel):
    """Page number based pagination"""
    page: int = Query(default=1, ge=1, description="Page number")
    page_size: int = Query(default=10, ge=1, le=100, description="Page size")
    total: int = 0
    data: list = []

    class Config:
        arbitrary_types_allowed = True
```

## Database Setup

```python
# app/extensions/db.py
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker
from app.settings import settings

# Sync engine
engine = create_engine(
    url=settings.SQLALCHEMY_DATABASE_SYNC_URL,
    pool_size=settings.SQLALCHEMY_POOL_SIZE,
    pool_recycle=settings.SQLALCHEMY_POOL_RECYCLE,
    pool_pre_ping=settings.SQLALCHEMY_POOL_PRE_PING,
    echo=settings.SQLALCHEMY_ECHO
)
session = sessionmaker(
    engine,
    autocommit=False,
    autoflush=False,
    expire_on_commit=False
)

# Async engine
async_engine = create_async_engine(
    url=settings.SQLALCHEMY_DATABASE_ASYNC_URL,
    pool_size=settings.SQLALCHEMY_POOL_SIZE,
    pool_recycle=settings.SQLALCHEMY_POOL_RECYCLE,
    pool_pre_ping=settings.SQLALCHEMY_POOL_PRE_PING,
    echo=settings.SQLALCHEMY_ECHO
)

async_session = async_sessionmaker(
    bind=async_engine,
    expire_on_commit=False,
    autocommit=False,
    autoflush=False
)
```

### Redis Cache

```python
# app/extensions/cache.py
import redis.asyncio as aioredis
from app.settings import settings


async def get_redis() -> aioredis.Redis:
    """Dependency for Redis connection"""
    return aioredis.from_url(settings.REDIS_URL, decode_responses=True)


class RedisCache:
    """Redis cache utility"""

    def __init__(self):
        self.redis: aioredis.Redis = None

    async def connect(self):
        self.redis = await get_redis()

    async def close(self):
        if self.redis:
            await self.redis.close()

    async def get(self, key: str) -> str:
        return await self.redis.get(key)

    async def set(self, key: str, value: str, expire: int = 3600):
        await self.redis.set(key, value, ex=expire)

    async def delete(self, key: str):
        await self.redis.delete(key)
```

### MongoDB

```python
# app/extensions/mongo.py
from motor.motor_asyncio import AsyncIOMotorClient, AsyncIOMotorDatabase
from app.settings import settings


class MongoDB:
    client: AsyncIOMotorClient = None
    db: AsyncIOMotorDatabase = None


mongodb = MongoDB()


async def get_mongo() -> AsyncIOMotorDatabase:
    """Dependency for MongoDB connection"""
    return mongodb.db


async def connect_mongo():
    """Connect to MongoDB on startup"""
    mongodb.client = AsyncIOMotorClient(settings.MONGODB_URL)
    mongodb.db = mongodb.client[settings.MONGODB_DB]


async def close_mongo():
    """Close MongoDB connection on shutdown"""
    if mongodb.client:
        mongodb.client.close()
```

```python
# app/extensions/__init__.py
from app.extensions.db import session, async_session
from app.extensions.cache import get_redis, aioredis
from app.extensions.mongo import get_mongo


async def get_db() -> AsyncSession:
    async with async_session() as db:
        try:
            yield db
            await db.commit()
        except Exception:
            await db.rollback()
            raise
        finally:
            await db.close()
```

## Security & Auth

### Password Hashing (pwdlib)

```python
# common/security.py
from pwdlib import PasswordHash

password_hash = PasswordHash.recommended()


def set_password(password: str) -> str:
    """Hash password"""
    return password_hash.hash(password)


def verify_password(password: str, password_hash_value: str) -> bool:
    """Verify password"""
    return password_hash.verify(password, password_hash_value)
```

### JWT Token

```python
# common/security.py (continued)
from datetime import datetime, timedelta
import jwt
from jwt import PyJWTError
from typing import Union, Any, Optional
from app.settings import settings


def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -> str:
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
    to_encode.update({"exp": expire})
    return jwt.encode(to_encode, settings.JWT_SECRET_KEY, algorithm=settings.ALGORITHM)


def create_refresh_token(data: dict, expires_delta: Optional[timedelta] = None) -> str:
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(days=settings.REFRESH_TOKEN_EXPIRE_DAYS)
    to_encode.update({"exp": expire})
    return jwt.encode(to_encode, settings.JWT_REFRESH_SECRET_KEY, algorithm=settings.ALGORITHM)
```

### OAuth2 with Scopes

```python
# app/core/oauth2.py
from fastapi import Security, Depends
from fastapi.security import OAuth2PasswordBearer
from jose import JWTError, jwt
from common.response import ErrCode, response_err
from common.security import create_access_token


oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/login")


async def get_current_active_user(current_user = Security(get_current_user, scopes=['user'])):
    return current_user


async def get_current_admin_user(current_user = Security(get_current_user, scopes=['admin'])):
    return current_user
```

## Exception Handlers

```python
# app/core/exceptions.py
from fastapi import FastAPI, Request
from fastapi.exceptions import RequestValidationError
from sqlalchemy.exc import IntegrityError, OperationalError
from common.response import ErrCode, response_err


def register_exceptions(app: FastAPI):
    @app.exception_handler(Exception)
    async def internal_err_handler(request: Request, exc: Exception):
        return response_err(ErrCode.COMMON_INTERNAL_ERR, detail=str(exc))

    @app.exception_handler(RequestValidationError)
    async def validation_error_handler(request: Request, exc: RequestValidationError):
        return response_err(ErrCode.REQUEST_PARAMS_ERROR, detail=exc.errors())

    @app.exception_handler(IntegrityError)
    async def integrity_error_handler(request: Request, exc: IntegrityError):
        return response_err(ErrCode.DB_INTEGRITY_ERROR, detail=str(exc.detail))

    @app.exception_handler(OperationalError)
    async def db_connection_error(request: Request, exc: OperationalError):
        return response_err(ErrCode.DB_CONNECTION_ERROR, detail=str(exc))
```

## API Module Template

```python
# app/api/user/views.py
from fastapi import APIRouter, Query, Body, Depends, Security, BackgroundTasks
from sqlalchemy import select
from typing import Optional

from common.response import ErrCode, response_ok, response_err
from common.pagation import PageNumberPagination
from common.security import set_password
from app.extensions import get_db, AsyncSession, get_redis, aioredis
from app.core.oauth2 import get_current_active_user
from app.api.user.models import User
from app.api.user.schemas import UserCreateSchema
from app.api.user.tasks import generate_user_avatar_task


router = APIRouter()


@router.post('/create', summary='Create user')
async def create_user(
    background_tasks: BackgroundTasks,
    args: UserCreateSchema,
    db: AsyncSession = Depends(get_db),
    redis: aioredis.Redis = Depends(get_redis),
    current_user: User = Security(get_current_active_user, scopes=['admin'])
):
    # Check if user exists
    existing = await db.scalar(select(User).where(User.username == args.username))
    if existing:
        return response_err(ErrCode.UNAME_HAS_OCCUPIED)

    user = User(
        username=args.username,
        password_hash=set_password(args.password),
        name=args.name or args.username,
        is_active=True,
        role=args.role
    )
    db.add(user)
    await db.commit()
    background_tasks.add_task(generate_user_avatar_task, user.id)
    return response_ok(data=user.to_dict(include=['id']))


@router.get('/list', summary='User list')
async def user_list(
    username: str = Query(default=None, description='Username'),
    paginate: PageNumberPagination = Depends(),
    current_user: User = Security(get_current_active_user, scopes=['admin'])
):
    query_filter = []
    if username:
        query_filter.append(User.username.ilike(f"%{username}%"))

    result_data = await paginate(User, query_filter)
    return response_ok(**result_data)


@router.get('/info', summary='User info')
async def user_info(
    current_user: User = Security(get_current_active_user, scopes=['user'])
):
    return response_ok(data=current_user.to_dict())
```

## Main Application Entry

```python
# main.py (project root)
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

from app.settings import settings
from app.api.router import register_router
from app.core.exceptions import register_exceptions
from app.core.middleware import register_middleware


@asynccontextmanager
async def lifespan(app: FastAPI):
    register_router(app)
    yield


app = FastAPI(
    title=settings.PROJECT_NAME,
    version=settings.VERSION,
    lifespan=lifespan,
    docs_url=settings.SWAGGER_DOCS_URL,
    redoc_url=settings.SWAGGER_REDOC_URL,
    openapi_url=settings.OPENAPI_URL,
)

register_middleware(app)
register_exceptions(app)
```

## Docker Configuration

```dockerfile
# docker/Dockerfile
FROM python:3.12-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE 8000

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
```

```yaml
# docker/docker-compose.yml
version: '3.8'

services:
  app:
    build: .
    ports:
      - "8000:8000"
    environment:
      - ENV=development
      - SQLALCHEMY_DATABASE_ASYNC_URL=mysql+asyncmy://user:pass@db:3306/app
      - REDIS_URL=redis://redis:6379/0
    depends_on:
      - db
      - redis
    volumes:
      - .:/app

  db:
    image: mysql:8
    environment:
      MYSQL_ROOT_PASSWORD: rootpass
      MYSQL_DATABASE: app
    command: --default-authentication-plugin=mysql_native_password

  redis:
    image: redis:7-alpine

volumes:
  mysql_data:
  redis_data:
```

## Implementation Workflow

When user requests a FastAPI project:

1. **Gather Requirements**: Project name, database, auth requirements
2. **Generate Structure**: Create directory structure
3. **Create Config**: Settings with multi-environment support
4. **Setup Response**: Response wrappers and error codes
5. **Setup Auth**: JWT with pwdlib password hashing
6. **Add Database**: SQLAlchemy with sync/async support
7. **Add Cache**: Redis integration
8. **Add Tasks**: Celery configuration
9. **Add Docker**: Containerization files
10. **Write README**: Documentation

Generate production-grade code with proper error handling, logging, and unified response format.

Related Skills

generator

16
from diegosouzapw/awesome-omni-skill

Générateur de Skill - Crée de nouveaux fichiers SKILL.md depuis les définitions YAML d'agents

EchoKit Config Generator

16
from diegosouzapw/awesome-omni-skill

Generate config.toml for EchoKit servers with interactive setup for ASR, TTS, LLM services, MCP servers, API key entry, and server launch

ck:project-management

16
from diegosouzapw/awesome-omni-skill

Track progress, update plan statuses, manage Claude Tasks, generate reports, coordinate docs updates. Use for project oversight, status checks, plan completion, task hydration, cross-session continuity.

bigconfig-generator

16
from diegosouzapw/awesome-omni-skill

Use this skill when creating or updating Bigeye monitoring configurations (bigconfig.yml files) for BigQuery tables. Works with metadata-manager skill.

audit-and-add-project-skills

16
from diegosouzapw/awesome-omni-skill

Audits project skills in .agent/skills/ and Codex skills for Cursor compatibility, then helps add compatible skills to .cursor/skills/. Use when the user wants to migrate project skills to Cursor, check if skills work with Cursor, or add existing skills to Cursor.

ai-image-generator

16
from diegosouzapw/awesome-omni-skill

使用 ModelScope 等平台生成 AI 图像。当用户需要生成图像、设计图标、创建角色立绘,或需要帮助编写 AI 绘画提示词时使用此技能。支持直接生成图像和仅优化提示词两种模式。

agent-project-manager

16
from diegosouzapw/awesome-omni-skill

Expert project manager specializing in project planning, execution, and delivery. Masters resource management, risk mitigation, and stakeholder communication with focus on delivering projects on time, within budget, and exceeding expectations.

thumbnail-generator

16
from diegosouzapw/awesome-omni-skill

Generate prompts for dev.to blog thumbnail/cover images in hand-drawn infographic style. Use when creating cover images, thumbnails, or featured images for blog posts. Recommended size 1000x420 pixels.

seedream-image-generator

16
from diegosouzapw/awesome-omni-skill

Generate images using the Doubao SeeDream API based on text prompts. Use this skill when users request AI-generated images, artwork, illustrations, or visual content creation. The skill handles API calls, downloads generated images to the project's /pic folder, and supports batch generation of up to 4 sequential images.

og-image-generator

16
from diegosouzapw/awesome-omni-skill

Generate and optimize Open Graph meta images for social media sharing. Use this skill when building web applications that need dynamic OG image generation with support for Vercel's @vercel/og library, pre-generated image storage, and social media optimization (Twitter Cards, Facebook, LinkedIn). Handles dynamic routes, performance optimization, and includes best practices for crawler compatibility and testing.

gemini-image-generator

16
from diegosouzapw/awesome-omni-skill

Generate and edit images using Google Gemini. Use when the user asks to generate, create, edit, or modify images.

didactic-content-generator

16
from diegosouzapw/awesome-omni-skill

Gere conteúdo didático de alta qualidade em HTML/CSS com ilustrações SVG, usando um sistema de Temas pré definidos e reutilizáveis. Capaz de criar ou editar apostilas, tutoriais e materiais educacionais que seguem filosofias pedagógicas claras.