Skip to main content

FastFort

Batteries-included authentication and admin framework for FastAPI.

Django-style model registration · Professional admin UI · JWT + session auth · Roles & permissions · Audit logging · SQLAlchemy & Tortoise · No Node.js required

CI License: MIT Python

[!WARNING] Early stage. 0.1.0 is the first release and the public API is not stable yet — before 1.0, a minor release may contain breaking changes, each one listed under a Breaking heading in the changelog. Pin a version.


Why FastFort?

Every FastAPI project rebuilds the same things from scratch: an admin panel, login, refresh tokens, roles, an audit trail. Django ships all of that out of the box. FastAPI does not.

FastFort fills that gap.

uv add "fastfort[sqlalchemy]"
# main.py
from fastapi import FastAPI
from fastfort import FastFort, FastFortSettings
from fastfort.orm.sqlalchemy import SQLAlchemyBackend

from app.db import Base, session_factory
from app.models import User

app = FastAPI()

fort = FastFort(
    settings=FastFortSettings(project_name="Shop"),
    backend=SQLAlchemyBackend(session_factory=session_factory, base=Base),
)
fort.set_user_model(User, identity_field="email")
fort.autodiscover("app")
fort.mount(app)
# app/products/admin.py
from fastfort import admin

from app.models import Product


@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    list_display = ("id", "name", "price", "is_active", "created_at")
    list_filter = ("is_active", "category")
    search_fields = ("name", "description")
    ordering = ("-created_at",)
    select_related = ("category",)
    icon = "box"  # drawn beside the sidebar entry

    # Offered once rows are selected. "delete" is built in; this adds another.
    actions = ("delete", "archive")

    @admin.action("Archive", icon="box")
    async def archive(self, adapter, objects):
        for product in objects:
            await adapter.update(product, {"is_active": False})
        return f"{len(objects)} products archived."

Create the first account and start the server:

uv run fastfort generate-secret --export      # a signing key
FF_PASSWORD=... uv run fastfort createsuperuser \
    --identity you@example.com --password-env FF_PASSWORD --no-input
uv run uvicorn main:app

Open http://127.0.0.1:8000/admin, sign in, and you have a list, a search box, filters, sortable columns, numbered pagination, row selection with bulk actions, and working create, edit and delete pages. Foreign keys become searchable pickers -- backed by an autocomplete endpoint once the target table outgrows a dropdown -- and many-to-many fields become removable chips.

None of it needs JavaScript to work. Every control is a real form input and every sort header a real link; the browser-side code upgrades them in place and gets out of the way when it is not there.

Field names are checked against the model when the admin is built, so a typo in list_display is a start-up error naming every problem at once -- not a 500 the first time someone opens that page.


Features

🎛 Django-style admin @admin.register, list_display, list_filter, search_fields, fieldsets, actions
🗑 Deletes you can trust The confirmation counts what actually goes: rows that cascade, rows kept with the link cleared, and rows that block the delete outright — refused with a sentence instead of a constraint violation
🎨 A UI you will not want to replace Light and dark themes, brand colour from a single setting, ⌘K command palette, full keyboard navigation, real mobile layout
🔐 Production-grade auth Argon2id hashing, JWT access/refresh, token rotation with reuse detection, login lockout, CSRF protection
👥 Roles and permissions Object-level, row-level and field-level access control
📝 Audit log Who changed what and when, with an old → new diff
🗄 Three databases SQLite · PostgreSQL · MySQL, with identical behaviour
🔌 ORM-agnostic SQLAlchemy 2.0 (async and sync) and Tortoise ORM behind one adapter contract
🌍 Eleven languages English, Uzbek, Russian, Turkish, German, French, Spanish, Chinese, Japanese, Korean and Arabic — the last of them right-to-left, which turns the whole layout around from one attribute. The catalogues ship in the package, so the admin is already translated the moment you install it — there is nothing to configure
⌨️ A CLI that matters createsuperuser so a fresh install has a way in, and check --deploy that exits non-zero
📤 Export The current view as CSV or Excel — filters, search and ordering included. No openpyxl, no pandas
📦 No Node.js CSS and JavaScript ship pre-built inside the package, served Brotli-compressed with a gzip fallback — 24 KB of CSS and 29 KB of JavaScript on the wire

How it is put together

UI (Jinja2 · CSS · HTMX)   ─┐
Admin (ModelAdmin, forms)  ─┤
Auth (tokens, permissions) ─┼──►  Spec layer (immutable, JSON-serialisable)  ◄── ORM adapters
Core (settings, registry)  ─┘

Everything above the spec layer is ORM-agnostic, and that boundary is enforced by tests rather than by convention. Adding a new ORM therefore never touches the admin or the UI, and a JSON API for a future SPA front end comes for free from the same specs the templates render.


Installation

uv add "fastfort[sqlalchemy,postgres]"    # PostgreSQL
uv add "fastfort[sqlalchemy,mysql]"       # MySQL
uv add "fastfort[sqlalchemy,sqlite]"      # SQLite
uv add "fastfort[all]"                    # everything

Requires Python 3.11 or newer.


Development

The only prerequisite is uv. No Node.js, ever.

uv sync --all-extras          # set up the environment
uv run pytest                 # tests (SQLite)
uv run pytest --db=all        # tests against all three databases (needs Docker)
uv run ruff check .           # linting
uv run mypy fastfort          # type checking
make check                    # every gate at once

See CONTRIBUTING.md before opening a pull request, and SECURITY.md to report a vulnerability.


License

MIT © Matnazar

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fastfort-0.2.1.tar.gz (436.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fastfort-0.2.1-py3-none-any.whl (362.7 kB view details)

Uploaded Python 3

File details

Details for the file fastfort-0.2.1.tar.gz.

File metadata

  • Download URL: fastfort-0.2.1.tar.gz
  • Upload date:
  • Size: 436.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for fastfort-0.2.1.tar.gz
Algorithm Hash digest
SHA256 b2916d09ad33c0bedda1a2baa5beb8a5c2023af808715af7217a0668a9bb8712
MD5 77916630de6d74accd6ed8634bc7cd74
BLAKE2b-256 ea3944eaf4fa23380b1c228eb38ebde2ed42eebf9d3657b8618c2d9d83f98edf

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastfort-0.2.1.tar.gz:

Publisher: publish.yml on Matnazar-Matnazarov/fastfort

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file fastfort-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: fastfort-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 362.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for fastfort-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 e270c130dbfb2da785e6ed12b17f10f629d6b8477a59f3f0f19024e6c844a9af
MD5 ebdcdd587de08a1c390845575e05f59f
BLAKE2b-256 ec7a64b27febe9ab3c33b5a4408bcc4af75e2c1f3342af0bc01eef3cbb75cb3d

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastfort-0.2.1-py3-none-any.whl:

Publisher: publish.yml on Matnazar-Matnazarov/fastfort

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page