make
Generate production-ready FastAPI modules and individual files. The primary FastKit CLI command — use make module for a full stack at once, or individual sub-commands to generate specific files.
make module
Generates a complete module with all six files in one command — the fastest path from idea to working endpoint.
Options
| Option | Short | Default | Description |
|---|---|---|---|
--dir | -d | modules | Root directory where the module folder is created |
--async | -a | False | Generate async repository, service, and router |
--force | -f | False | Overwrite existing files |
Examples
# Basic sync module
fastkit make module Invoice
# Async module
fastkit make module Invoice --async
# Custom output directory
fastkit make module Invoice --dir src/modules
# Compound name (PascalCase or snake_case — both work)
fastkit make module InvoiceItem
fastkit make module invoice_item # same result
# Overwrite existing files
fastkit make module Invoice --force
Generated files
BaseWithTimestamps and IntIdMixinCreate, Update, and Response schemasRepository (or AsyncRepository with --async)BaseCrudService (or AsyncBaseCrudService with --async)make module also automatically registers the new model in alembic/env.py so it's picked up by the next fastkit migrate make.
make model
Generates only the SQLAlchemy model file. Useful when you have an existing module and need to add a model separately.
| Option | Short | Default | Description |
|---|---|---|---|
--path | -p | . | Target directory for the generated file |
--force | -f | False | Overwrite existing file |
fastkit make model Invoice
fastkit make model Invoice --path modules/invoices
Generated models.py
from fastkit_core.database import BaseWithTimestamps, IntIdMixin
# from fastkit_core.database import UUIDMixin, SoftDeleteMixin, SlugMixin
class Invoice(BaseWithTimestamps, IntIdMixin):
__tablename__ = "invoices"
# Define your fields here
make schema
Generates only the Pydantic schemas file with Create, Update, and Response classes.
| Option | Short | Default | Description |
|---|---|---|---|
--path | -p | . | Target directory for the generated file |
--force | -f | False | Overwrite existing file |
fastkit make schema Invoice
fastkit make schema Invoice --path modules/invoices
Generated schemas.py
from fastkit_core.validation import BaseSchema
class InvoiceCreate(BaseSchema):
pass # Define your fields here
class InvoiceUpdate(BaseSchema):
pass # All fields optional for partial updates
class InvoiceResponse(BaseSchema):
id: int
model_config = {"from_attributes": True}
make repository
Generates only the repository file. Supports both sync and async variants.
| Option | Short | Default | Description |
|---|---|---|---|
--path | -p | . | Target directory for the generated file |
--async | -a | False | Generate async repository using AsyncRepository |
--force | -f | False | Overwrite existing file |
fastkit make repository Invoice
fastkit make repository Invoice --async
fastkit make repository Invoice --path modules/invoices
from fastkit_core.database import Repository
from sqlalchemy.orm import Session
from .models import Invoice
class InvoiceRepository(Repository[Invoice]):
def __init__(self, session: Session):
super().__init__(Invoice, session)
from fastkit_core.database import AsyncRepository
from sqlalchemy.ext.asyncio import AsyncSession
from .models import Invoice
class InvoiceRepository(AsyncRepository[Invoice]):
def __init__(self, session: AsyncSession):
super().__init__(Invoice, session)
make service
Generates only the service file. The place for your business logic — add lifecycle hooks and custom methods after generation.
| Option | Short | Default | Description |
|---|---|---|---|
--path | -p | . | Target directory for the generated file |
--async | -a | False | Generate async service using AsyncBaseCrudService |
--force | -f | False | Overwrite existing file |
fastkit make service Invoice
fastkit make service Invoice --async
from fastkit_core.services import BaseCrudService
from sqlalchemy.orm import Session
from .models import Invoice
from .schemas import InvoiceCreate, InvoiceUpdate, InvoiceResponse
from .repository import InvoiceRepository
class InvoiceService(BaseCrudService[Invoice, InvoiceCreate, InvoiceUpdate, InvoiceResponse]):
def __init__(self, session: Session):
super().__init__(
InvoiceRepository(session),
response_schema=InvoiceResponse
)
# Add your business logic, lifecycle hooks, and custom methods here
from fastkit_core.services import AsyncBaseCrudService
from sqlalchemy.ext.asyncio import AsyncSession
from .models import Invoice
from .schemas import InvoiceCreate, InvoiceUpdate, InvoiceResponse
from .repository import InvoiceRepository
class InvoiceService(AsyncBaseCrudService[Invoice, InvoiceCreate, InvoiceUpdate, InvoiceResponse]):
def __init__(self, session: AsyncSession):
super().__init__(
InvoiceRepository(session),
response_schema=InvoiceResponse
)
# Add your async business logic, lifecycle hooks, and custom methods here
make router
Generates only the router file with all five CRUD endpoints pre-wired to the service.
| Option | Short | Default | Description |
|---|---|---|---|
--path | -p | . | Target directory for the generated file |
--async | -a | False | Generate async router using get_async_db |
--force | -f | False | Overwrite existing file |
fastkit make router Invoice
fastkit make router Invoice --async
Generated endpoints
| Handler | Method | Path | Description |
|---|---|---|---|
index | GET | /invoices | Paginated list with page and per_page params |
show | GET | /invoices/{id} | Single record — 404 if not found |
store | POST | /invoices | Create — returns 201 |
update | PUT | /invoices/{id} | Update — partial update supported |
destroy | DELETE | /invoices/{id} | Delete — returns 204 |
from fastapi import APIRouter, Depends
from fastkit_core.database import get_db
from fastkit_core.http import success_response, paginated_response
from sqlalchemy.orm import Session
from .schemas import InvoiceCreate, InvoiceUpdate
from .service import InvoiceService
router = APIRouter(prefix="/invoices", tags=["invoices"])
def get_service(session: Session = Depends(get_db)) -> InvoiceService:
return InvoiceService(session)
@router.get("/")
def index(page: int = 1, per_page: int = 20, svc: InvoiceService = Depends(get_service)):
items, meta = svc.paginate(page=page, per_page=per_page)
return paginated_response(items=[i.model_dump() for i in items], pagination=meta)
@router.get("/{id}")
def show(id: int, svc: InvoiceService = Depends(get_service)):
return success_response(data=svc.find_or_fail(id).model_dump())
@router.post("/", status_code=201)
def store(data: InvoiceCreate, svc: InvoiceService = Depends(get_service)):
return success_response(data=svc.create(data).model_dump())
@router.put("/{id}")
def update(id: int, data: InvoiceUpdate, svc: InvoiceService = Depends(get_service)):
return success_response(data=svc.update(id, data).model_dump())
@router.delete("/{id}", status_code=204)
def destroy(id: int, svc: InvoiceService = Depends(get_service)):
svc.delete(id)
from fastapi import APIRouter, Depends
from fastkit_core.database import get_async_db
from fastkit_core.http import success_response, paginated_response
from sqlalchemy.ext.asyncio import AsyncSession
from .schemas import InvoiceCreate, InvoiceUpdate
from .service import InvoiceService
router = APIRouter(prefix="/invoices", tags=["invoices"])
def get_service(session: AsyncSession = Depends(get_async_db)) -> InvoiceService:
return InvoiceService(session)
@router.get("/")
async def index(page: int = 1, per_page: int = 20, svc: InvoiceService = Depends(get_service)):
items, meta = await svc.paginate(page=page, per_page=per_page)
return paginated_response(items=[i.model_dump() for i in items], pagination=meta)
@router.get("/{id}")
async def show(id: int, svc: InvoiceService = Depends(get_service)):
return success_response(data=(await svc.find_or_fail(id)).model_dump())
@router.post("/", status_code=201)
async def store(data: InvoiceCreate, svc: InvoiceService = Depends(get_service)):
return success_response(data=(await svc.create(data)).model_dump())
@router.put("/{id}")
async def update(id: int, data: InvoiceUpdate, svc: InvoiceService = Depends(get_service)):
return success_response(data=(await svc.update(id, data)).model_dump())
@router.delete("/{id}", status_code=204)
async def destroy(id: int, svc: InvoiceService = Depends(get_service)):
await svc.delete(id)
Common Options
All make sub-commands share these patterns:
--force / overwriting files
By default FastKit CLI refuses to overwrite existing files to prevent accidental data loss. Use --force to override:
# Will fail if modules/invoices/ already exists
fastkit make module Invoice
# Overwrites all files in modules/invoices/
fastkit make module Invoice --force
--force overwrites files without confirmation. Commit your changes before using it.
--async vs sync
Choose sync or async based on your project's database setup:
- Uses
Sessionfromget_db - Uses
Repository - Uses
BaseCrudService - Standard
defhandlers - Simpler — good for most projects
- Uses
AsyncSessionfromget_async_db - Uses
AsyncRepository - Uses
AsyncBaseCrudService async defhandlers withawait- Better for high-concurrency I/O workloads
Sub-command summary
| Sub-command | Generates | Supports --async |
|---|---|---|
make module | All 6 files | ✓ |
make model | models.py | — |
make schema | schemas.py | — |
make repository | repository.py | ✓ |
make service | service.py | ✓ |
make router | router.py | ✓ |