Skip to content
New documentation  ยท  See what changed

Extensible admin interfaces
for FastAPI & Starlette

Instantly generate a comprehensive administrative UI from your SQLAlchemy, SQLModel, Beanie, MongoEngine, or Tortoise ORM models. Built on the modern Tabler UI kit, starlette-admin delivers robust list views, auto-generated forms, data exports, and secure authentication. Configure your entire interface in Python without writing any frontend code.

pip install starlette-admin
starlette-admin dashboard showing statistical widgets, recent activity tables, and a sidebar for model views

Built-in features

Get everything you need right out of the box. Every core feature includes well-documented extension points to support your specific requirements.

Everything is Python

Build complete administrative interfaces using a pure Python API designed for rapid development, intuitive syntax, and long-term maintainability.

Mount the admin panel

Register a model and mount the admin panel on any FastAPI or Starlette application, then run it using fastapi dev and open /admin.

View the documentation

main.py
from fastapi import FastAPI
from sqlalchemy import create_engine
from starlette_admin.contrib.sqla import Admin, ModelView

from models import Base, Post

engine = create_engine("sqlite:///blog.db")
Base.metadata.create_all(engine)

app = FastAPI()

admin = Admin(engine, title="Blog Admin", secret_key="change-me")
admin.add_view(ModelView(Post, icon="fa fa-newspaper"))
admin.mount_to(app)

Views

Tune search, sorting, default ordering, and export formats using plain class attributes. Arrange your create and edit forms using form_layout.

View the documentation

views.py
from starlette_admin.contrib.sqla import ModelView


class PostView(ModelView):
    fields = ["id", "title", "author", "content", "published", "created_at"]
    searchable_fields = ["title", "content"]
    fields_default_sort = [("created_at", True)]
    exporters = ["csv", "xlsx", "json"]
    form_layout = [
        ("title", "author"),
        "content",
        ("published", "created_at"),
    ]


admin.add_view(PostView(Post, icon="fa fa-newspaper"))

Fields

Override any auto-detected field to control validation, per-page visibility, and how the system reads and displays values.

View the documentation

views.py
from starlette_admin import DateTimeField, RequestAction, StringField, TextAreaField
from starlette_admin.contrib.sqla import ModelView


class PostView(ModelView):
    fields = [
        "id",
        StringField("title", required=True, help_text="Shown on the blog"),
        TextAreaField("content", exclude_from_list=True),
        StringField(
            "author_email",
            getter=lambda request, obj: obj.author.email,
            formatter={RequestAction.LIST: lambda request, value: value or "unset"},
        ),
        DateTimeField("created_at", read_only=True, exclude_from_create=True),
    ]

Actions

Attach business operations using a simple decorator. Confirmation modals, custom forms, and flash messages are built directly into the framework.

View the documentation

views.py
from starlette.requests import Request
from starlette_admin import ActionSelection, action, flash
from starlette_admin.contrib.sqla import ModelView


class ArticleView(ModelView):
    actions = ["publish", "delete"]

    @action(
        name="publish",
        text="Mark as published",
        confirmation="Publish the selected articles?",
        submit_btn_text="Yes, publish",
    )
    async def publish(self, request: Request, selection: ActionSelection) -> None:
        articles = await selection.rows()
        for article in articles:
            article.published = True
        flash(request, f"{len(articles)} articles published.", "success")

Authentication

Implement three standard methods around your own credential check. The system handles the login page, sessions, and redirects for you.

View the documentation

auth.py
from starlette.requests import Request
from starlette_admin.auth import AdminUser, AuthProvider, LoginFailed


class MyAuthProvider(AuthProvider):
    async def login(self, username, password, remember_me, request: Request) -> None:
        if not await check_credentials(username, password):
            raise LoginFailed("Invalid username or password")
        request.session["username"] = username

    async def authenticate(self, request: Request) -> AdminUser | None:
        if username := request.session.get("username"):
            return AdminUser(username=username)
        return None

    async def logout(self, request: Request) -> None:
        request.session.clear()


admin = Admin(engine, auth_provider=MyAuthProvider(), secret_key=SECRET)

Dashboard

Compose the admin home page using statistic, chart, and table widgets that query live data on every request.

View the documentation

dashboard.py
from starlette_admin import CardRowWidget, ChartWidget, CustomView, StatWidget

dashboard = CardRowWidget(
    children=[
        StatWidget(title="Orders", value_callback=count_orders, countup=True),
        StatWidget(title="Revenue", value_callback=sum_revenue, color="success"),
        ChartWidget(title="Sales", chart_type="area", series_callback=sales_series),
    ]
)

admin = Admin(
    engine,
    title="Shop Admin",
    secret_key="change-me",
    index_view=CustomView(menu_label="Dashboard", icon="fa fa-home", widget=dashboard),
)

Plugins & extensions

Every layer is replaceable. Ship features as self-contained plugins or hook into any of the dedicated extension points to tailor the framework to your domain.

Drop-in plugins

Zero-boilerplate plugins

Install a plugin package and pass it directly to your Admin instance. Fields, converters, templates, and assets wire themselves together automatically, delivering complex features instantly.

from starlette_admin_geospatial import GeospatialPlugin
from starlette_admin.contrib.sqla import Admin

admin = Admin(
    engine,
    plugins=[GeospatialPlugin(default_zoom=13)],
)
Read the plugins guide
Extension points

Hook into any component

Predefined interfaces allow you to swap or augment each concern independently. Subclass the base you need and register it. You can customize everything from the authentication flow to the export formats.

Explore all extension points