Docs / fastkit-cli / make

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.

fastkit make module <name> [OPTIONS]

Options

OptionShortDefaultDescription
--dir-dmodulesRoot directory where the module folder is created
--async-aFalseGenerate async repository, service, and router
--force-fFalseOverwrite existing files

Examples

bash
# 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

__init__.py
Package init — exports model, service and router
models.py
SQLAlchemy model with BaseWithTimestamps and IntIdMixin
schemas.py
Pydantic Create, Update, and Response schemas
repository.py
Extends Repository (or AsyncRepository with --async)
service.py
Extends BaseCrudService (or AsyncBaseCrudService with --async)
router.py
FastAPI router with index, show, store, update, destroy endpoints

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.

fastkit make model <name> [OPTIONS]
OptionShortDefaultDescription
--path-p.Target directory for the generated file
--force-fFalseOverwrite existing file
bash
fastkit make model Invoice
fastkit make model Invoice --path modules/invoices

Generated models.py

python
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.

fastkit make schema <name> [OPTIONS]
OptionShortDefaultDescription
--path-p.Target directory for the generated file
--force-fFalseOverwrite existing file
bash
fastkit make schema Invoice
fastkit make schema Invoice --path modules/invoices

Generated schemas.py

python
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.

fastkit make repository <name> [OPTIONS]
OptionShortDefaultDescription
--path-p.Target directory for the generated file
--async-aFalseGenerate async repository using AsyncRepository
--force-fFalseOverwrite existing file
bash
fastkit make repository Invoice
fastkit make repository Invoice --async
fastkit make repository Invoice --path modules/invoices
python
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)
python
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.

fastkit make service <name> [OPTIONS]
OptionShortDefaultDescription
--path-p.Target directory for the generated file
--async-aFalseGenerate async service using AsyncBaseCrudService
--force-fFalseOverwrite existing file
bash
fastkit make service Invoice
fastkit make service Invoice --async
python
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
python
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.

fastkit make router <name> [OPTIONS]
OptionShortDefaultDescription
--path-p.Target directory for the generated file
--async-aFalseGenerate async router using get_async_db
--force-fFalseOverwrite existing file
bash
fastkit make router Invoice
fastkit make router Invoice --async

Generated endpoints

HandlerMethodPathDescription
indexGET/invoicesPaginated list with page and per_page params
showGET/invoices/{id}Single record — 404 if not found
storePOST/invoicesCreate — returns 201
updatePUT/invoices/{id}Update — partial update supported
destroyDELETE/invoices/{id}Delete — returns 204
python
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)
python
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:

bash
# 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:

Sync (default)
  • Uses Session from get_db
  • Uses Repository
  • Uses BaseCrudService
  • Standard def handlers
  • Simpler — good for most projects
Async (--async)
  • Uses AsyncSession from get_async_db
  • Uses AsyncRepository
  • Uses AsyncBaseCrudService
  • async def handlers with await
  • Better for high-concurrency I/O workloads

Sub-command summary

Sub-commandGeneratesSupports --async
make moduleAll 6 files
make modelmodels.py
make schemaschemas.py
make repositoryrepository.py
make serviceservice.py
make routerrouter.py