Django,
fully assembled
Declare a model once and SmallStack serves it every way at once—an admin app, a REST backend for your React frontend, an MCP server for Claude, and a fast search engine—with OpenAPI docs, webhooks, and feeds on the same SQLite file, behind one zero-downtime deploy.
The same class declaration produces an HTML interface, a REST endpoint, an MCP tool, full-text search, and a terminal CLI. Add a field, get a column, a JSON key, a tool argument, and a search index—everywhere at once.
Five surfaces from one declaration.
A CRUDView bound to a model
derives its own list, detail, create, update, and delete tools—then exposes them on the
surfaces you opt into.
# apps/tickets/views.py class TicketCRUDView(CRUDView): model = Ticket list_columns = ["id", "title", "status"] enable_api = True # REST + OpenAPI enable_mcp = True # tools for Claude enable_search = True # full-text + RAG tool
tickets_list, tickets_get, etc.—ready for Claude.
search_tickets MCP tool for retrieval (RAG).
sc ls, get, search, staff-gated new/set/rm—same ops, --json everywhere.
SmallStack isn't one kind of app. It's a small backend that drops into your architecture and plays whatever role you need—usually several at once.
Not an app type. A role you fill.
A polished admin
Auth, profiles, five-palette light/dark, table views, modal editors, filters, breadcrumbs—the internal tool you'd build anyway.
A backend for your frontend
REST with token auth and OpenAPI 3.0, plus bundled typed clients for React, Svelte, Solid & Streamlit. Point your SPA at it.
An MCP server for AI
OAuth + JSON-RPC tools derived from your models—Claude Desktop and the Connectors UI work with no setup.
A search engine
Real full-text search—FTS5 on SQLite, tsvector on Postgres—ranked, with a Ctrl-K omnibar and an MCP tool.
An integration hub
Signed webhooks in and out, RSS/Atom publish + consume, and Swagger + ReDoc for every endpoint. The seam between your systems.
A scheduled task runner
One-shot jobs plus recurring @scheduled work—cron, interval, or once—with a themed UI. No Redis, Celery, or beat.
Real full-text search, built in—not a LIKE
query. Ranked, fast, and the same code path on SQLite or Postgres.
A search engine, included.
Add enable_search = True
and a model gets a real index—FTS5 with BM25 ranking on
SQLite, a tsvector + GIN
index on Postgres—self-provisioned at migrate, no migration to write.
- Ranked & weighted—per-field
search_weighttunes what wins, with snippets and prefix matching. - Four ways in—a Ctrl-K omnibar, a
/smallstack/search/page, a REST endpoint, and asearch_XMCP tool. - SearchBuilder—define tailored variants (admin, public, api), each with its own MCP tool and JSON serialization. No DRF.
- Retrieval for AI—that
search_Xtool is RAG: Claude answers from your own records.
# One flag turns a model into a search source. class TicketCRUDView(CRUDView): model = Ticket enable_search = True search_fields = ["title", "description"] # You now have, with no extra code: # • FTS5 / tsvector index, self-provisioned # • omnibar + /search/ page + REST # • search_tickets(query, limit) MCP tool
The backend everything else talks to—your React app, your automations, and the systems next door.
The backend everything else talks to.
Every enable_api model is a
documented REST resource. OpenAPI 3.0 feeds
Swagger UI and ReDoc out of the box—hand the
schema to any client or codegen.
- A backend for React—bundled typed TypeScript/JS and single-file Python clients ship in
clients/: token auth, CRUD helpers, field-error maps, always API-version-matched. - Webhooks, both ways—signed outbound on change, verified inbound; Zapier, n8n, Stripe, and Slack are plug-ins on four seams.
- Feeds, both ways—publish any model as RSS/Atom, or consume an external feed on a schedule.
- Live docs—
/api/docs/(Swagger),/api/redoc/(ReDoc),/api/schema/openapi.json.
// Your SPA, talking to SmallStack — no SDK to publish. import { SmallStackClient } from 'smallstack-sdk-js' const api = new SmallStackClient({ baseUrl: API_URL }) await api.auth.login('admin', 'admin') const items = api.resource('/api/inventory/items') const page = await items.list({ q: 'drill', status: 'active' }) // typed rows, token handled, errors → field map
Same engine, two starters. smallstack-tabler is a downstream fork that tracks this repo and swaps the chrome.
Two starters for two shapes of work.
For CRUD & headless work
Django admin's base CSS, customized per palette—no extra framework. Light/dark with 5 palettes; HTMX in every CRUDView. The sweet spot for internal admins, REST APIs, and MCP servers.
When the UI is the product
Forks & tracks smallstack; swaps the chrome for Tabler. Dashboards, charts, kanban, calendar—anywhere a public-grade UI matters as much as the data.
Boring infrastructure, already done. Thirteen admin surfaces wired into the sidebar before you write a line.
The admin you'd build anyway, already built.
@scheduled jobs.
Most apps don't need the cluster they were architected for. SmallStack is built around that admission—lightweight, boring, and useful for years without a rebuild.
Unapologetically SQLite.
One file. Five years of customers. Zero rebuilds.
New in v0.13.0. Operational docs that live in the app—versioned, searchable, and reachable from every surface.
A runbook your app remembers.
Runbook ships in core. Write Markdown in the browser, keep an immutable version on every save, and find anything with full-text search. Set retention policies, export a runbook to a portable ZIP, restore any past version—nothing is ever destructive.
# the same doc, straight from your shell — the rb CLI rb find "postgres upgrade" # → ops/postgres-major-upgrade v7 rb cat ops/postgres-major-upgrade # …or let Claude call search_runbook_documents # versioned · searchable · OAuth + bearer
Every app ships with the skill files Claude Code needs to understand it. Open the repo, start vibing.
Vibe-code with Claude—and serve it, too.
Two sides of the same idea. SmallStack is readable by AI (skill files for the theme, CRUD, MCP, deployment) and serves AI—through a first-class MCP server that exposes your existing models as tools.
- CLAUDE.md at the root: your project's onboarding doc.
- 20+ skill files teaching the stack one pattern at a time.
- Ten-minute MCP walkthrough from
enable_mcp = Trueto Claude calling your tools. - Retrieval built in—the
search_Xtool is the lowest-friction RAG; Claude answers from your own records.
# Two flags: act on data, and find it. class TicketCRUDView(CRUDView): model = Ticket enable_mcp = True enable_search = True # That's it. Claude Desktop sees: # • tickets_list (search + filter) # • tickets_get (by id) # • tickets_create / update / delete # • search_tickets (full-text → RAG) # All authenticated by OAuth + bearer.
Three commands to a running app.
Free, MIT-licensed, self-hosted in minutes. Managed hosting from $15 / month when you'd rather not.