Admin panels
in pure Go
Typed Grid, Form, and Detail builders on GORM —
server-rendered, RBAC included, one binary, no Node.
Typed builders
Grid / Form / Detail declared in Go with generics. Callbacks receive your model type — never map[string]any.
Zero-config CRUD
steward.Register[User](app) alone yields a working resource: list, create, edit, detail, delete. Override any field when you need to.
RBAC & menus built in
Roles, permissions with HTTP path matching, per-row policies, and a drag-and-drop menu manager — administered from the panel itself.
One binary, no Node
The UI (Tailwind + Basecoat + htmx) is compiled ahead of time and shipped inside your binary via go:embed. No Node at build or runtime.
Headless when you need it
Every resource endpoint also speaks JSON via Accept: application/json — a REST API for free, from the same handlers.
Scaffolding CLI
Generate resources from a field spec, a live database, or a Go struct — with database-type → field-type inference.
Versioned migrations
Embedded framework migrations plus a batch-aware runner for your own. No silent AutoMigrate schema drift.
Background worker
Cron-style jobs run in a dedicated worker process — the same binary, deployed and scaled independently of the panel.
Boot-time verification
Every column reference in your grids, forms, and filters is checked at startup against the parsed schema — not at click time.
Declare it. Steward renders it.
app, _ := steward.New(steward.Config{DB: db, SecretKey: key})
posts := steward.Register[Post](app).Title("Posts").Icon("news")
posts.Grid(func(g *steward.Grid[Post]) {
g.Column("Title").Limit(40).Sortable()
g.Column("Status").Badge(map[any]string{"draft": "secondary", "published": "green"})
g.QuickSearch("Title", "Body")
})
posts.Form(func(f *steward.Form[Post]) {
f.Text("Title").Rules("required|max:255")
f.Markdown("Body")
})
ginsteward.Mount(router, app) // or mount app as a plain http.Handler