Skip to content

Sillo is the buildsmith framework for APIs, real-time systems and production backends: fast, async, and built with everything you need to ship, with the ORM, authentication, admin, queues, scheduler and WebSockets already in place.

Sillo is the buildsmith framework: fast, async, and built with everything you need to ship.

The language does not change. You write the same Python, with the same type hints and the same async/await you already know. What changes is how much of the backend is waiting for you when you start: routing, validation, dependency injection, the ORM, authentication, sessions, background jobs, scheduling, caching, WebSockets, the admin, and the testing tools are all first-party modules that share one configuration model.

Each of those is a solved problem, and there are good packages for every one of them. The work that remains is the fitting: reconciling interfaces, configuration styles, failure modes, and upgrade cycles that were never designed against each other. Sillo does that fitting once, so your time goes into the product instead.

Sillo Core is the open foundation of the framework. It is designed to help a project start small and grow without replacing its architecture every time the product becomes more real.

A Sillo application can begin with one route:

from sillo import SilloApp
app = SilloApp()
@app.get("/")
async def home(request, response):
return response.json({"message": "Hello from Sillo"})

From there, the same application model can grow into validated endpoints, authenticated routes, database-backed records, queues, scheduled work, WebSocket channels, and operational tooling.

Sillo is built around a small set of concepts that appear consistently across the framework.

ConceptWhat it means
SilloAppThe application object. It owns routes, middleware, lifecycle hooks, state, and framework configuration.
RequestThe incoming HTTP boundary: headers, query params, path params, body data, cookies, user state, and request-scoped data.
ResponseA fluent response builder for JSON, text, HTML, files, streams, redirects, cookies, headers, and status codes.
RoutesDecorated functions or router definitions that bind HTTP methods and paths to handlers.
MiddlewareRequest/response pipeline units for cross-cutting concerns such as CORS, auth, sessions, rate limits, ETags, and content negotiation.
Validationrequest_model turns untrusted request bodies into validated Pydantic models at the route boundary.
Dependency InjectionDepend wires services, shared state, request-aware providers, and reusable business logic into handlers.
RecordSillo’s database layer on top of Tortoise ORM for models, setup, serialization, casting, scopes, pagination, and persistence helpers.
WorkloadsJobs, queues, events, scheduler managers, and background work that run outside the request cycle.
WebSocketsReal-time connections, consumers, channels, and broadcast patterns for interactive systems.
TestingTest clients and framework patterns for exercising routes, validation, dependencies, auth, jobs, and application behaviour.

These concepts recur across the framework in the same shape. Reading one subsystem teaches you how to read the next, so no feature feels like it was borrowed from somewhere else.

This example shows a validated endpoint, path parameter, and response object working together.

from pydantic import BaseModel
from sillo import SilloApp
from sillo.core.http import Request, Response
app = SilloApp()
class CreateProject(BaseModel):
name: str
private: bool = False
@app.post("/teams/{team_id}/projects", request_model=CreateProject)
async def create_project(
request: Request,
response: Response,
team_id: str,
project: CreateProject,
):
return response.json(
{
"team_id": team_id,
"project": project.model_dump(),
"status": "created",
},
status_code=201,
)

What is happening:

  • team_id comes from the path and is passed into the handler.
  • request_model=CreateProject validates the request body.
  • The validated Pydantic object can be injected into the handler.
  • The response object builds a JSON response with a status code.

These are first-party modules, in the framework, each with a page in these docs:

  • async ASGI application foundation
  • routing, route groups, routers, and sub-apps
  • request and response helpers
  • request validation with Pydantic
  • dependency injection
  • middleware pipeline
  • CORS, CSRF, cookies, sessions, and security helpers
  • authentication, permissions, API keys, JWT, and session auth
  • Record ORM layer with database setup, models, casts, scopes, pagination, factories, and upserts
  • background jobs, queues, workers, events, and scheduling
  • caching with memory and Redis-compatible backends
  • WebSockets, consumers, channels, and real-time patterns
  • OpenAPI generation
  • static files, templating, file uploads, and streaming responses
  • test clients and testing utilities
  • HTTP client utilities
  • content negotiation, ETags, request lifecycle helpers, and protocol status constants under sillo.http

Sillo is useful for many backend-heavy products:

  • JSON APIs for web and mobile applications
  • SaaS backends with teams, users, roles, billing, jobs, and dashboards
  • internal tools and admin systems
  • real-time applications using WebSockets and channels
  • workflow systems with queues, retries, and scheduled jobs
  • data-backed business platforms with records, pagination, permissions, and audit-friendly patterns
  • API gateways and integration services
  • background processing systems
  • customer portals and product backends
  • applications that need to move from prototype to production without changing frameworks

Sillo is designed for developers and organisations building serious software with Python.

It is especially useful for:

  • independent developers who want a productive framework that can grow with a project
  • startups that need speed without accumulating avoidable operational debt
  • product teams building APIs, SaaS products, internal systems, and real-time applications
  • agencies that want repeatable backend foundations for client work
  • mid-market engineering teams that need standardisation, visibility, and governance
  • enterprise teams that care about security, lifecycle, compatibility, deployment choice, and operational clarity
  • educators and communities teaching modern Python backend development

Sillo is less suitable if you only need a tiny script, a one-off HTTP handler, or a framework that intentionally avoids owning anything beyond routing.

Writing a route or a database query is rarely the hard part. The time goes into the system around them: making a dozen well-built components agree on configuration, on how they start and stop, on what a user is, and on what happens when one of them fails.

Sillo puts those pieces in place already agreeing with each other. That coherence shows up in small, checkable ways. One auth= declaration gates a route and writes its securityScheme into the OpenAPI document, so the gate and the spec cannot drift apart. The scheduler registers on app.state and starts with the application lifecycle. Range requests, ETags, and content negotiation are middleware rather than something each project rewrites.

The framework is guided by these principles:

  • Strong defaults, open boundaries.
  • Convenience without mystery.
  • Documentation is part of the interface.
  • Compatibility and upgrade paths matter.
  • Anything the framework does on your behalf is something you can read, override, or replace.

Sillo is opinionated where a clear default helps, and transparent at the boundaries. Auth backends, middleware, cache drivers, session stores, and hashing algorithms are all contracts you can implement yourself.

Sillo is not a drop-in clone of another Python framework, and the frameworks below are all good at what they are built for. The difference is scope: how much of the application is first-party and designed against the rest.

FrameworkGood atWhere Sillo differs
FlaskMinimal apps, simple routing, extension-based composition.A broader first-party surface: validation, DI, auth, records, jobs, scheduling, caching, WebSockets, and testing all in the framework.
FastAPITyped APIs, Pydantic validation, async endpoints.The same typed, async request layer, plus the ORM, admin, durable queue, and scheduler as first-party modules on one config model.
DjangoA complete web framework with ORM, admin, and a mature ecosystem.The same completeness, built async-first around async/await handlers, background workloads, and real-time systems.
StarletteA low-level ASGI toolkit and primitives.A higher-level application framework over the same ASGI foundation, so the application concerns above are already assembled.

Ecosystem size and years in production are real advantages, and Django, Flask, and FastAPI have both. Sillo’s argument is scope and coherence, not maturity.

sillo is an ASGI framework, which means it speaks the same protocol as uvicorn, granian, hypercorn, and every ASGI middleware in the ecosystem. Everything below builds on that one interface.

A request arrives at the server, which hands sillo a scope, a receive, and a send. sillo builds a Request, runs it through the middleware stack, matches it against the router, resolves dependencies and validates inputs, calls your handler, and serializes what comes back.

Around that core sit optional subsystems, each independent: an ORM layer, background work, WebSockets, templating, caching, mail, and an HTTP client. None of them are required. An application that only serves JSON needs none of them.

The path through the documentation depends on what you are building.

A JSON API. RoutingHandlersValidationError Handling. That is enough to build something real. Add Record when you need a database and Authentication when you need users.

A server-rendered application. RoutingTemplatingSessionsCSRF. The last is not optional if your forms authenticate with cookies.

Something real-time. WebSockets first, and read its scaling section before you design anything, because the answer changes what you build.

Anything going to production. Security, Startup & Shutdown, and Concurrency, in that order. The third one is where most performance surprises come from.

These guides document what the framework does, including where it does something surprising or wrong. Where a function has a defect, the page covering it says so, shows the failure, and gives a working alternative.

That is deliberate. A guide that describes intended behaviour is a guide that costs you an afternoon the first time reality differs. Every :::danger and :::caution block in these pages marks something verified by running it.

A few things recur in every guide and are worth knowing once.

Handlers take request, response. Everything after those two is injected: validated parameters, dependencies, the request body.

app.state is process-wide, request.state is per-request. The first is written by lifespan hooks; the second by middleware.

setup_* functions are idempotent. setup_record, setup_work, and setup_mail each store an object in app.state and register lifecycle hooks, and calling one twice returns the existing object rather than reconfiguring.

Async by default. The framework, the ORM, and the HTTP client are all async. Synchronous handlers work and run in a thread; synchronous calls inside an async handler block everything.

Every page ends with “What not to do”. Those lists are the compressed version of the page, and they are the part worth re-reading before shipping.

The guides are organised by subsystem, and the sidebar mirrors the package layout, so sillo.record is under Record and sillo.work under Work. If you know the module, you can find the page.

For questions the guides do not answer, the source is small enough to read. Most modules are a few hundred lines, the abstractions are shallow, and the answer to “what does this actually do” is usually one file away, which is how several of the warnings in these pages were found.

These guides assume working Python and a rough familiarity with HTTP: methods, status codes, headers, and what a request body is. They do not assume prior experience with an async framework; where async/await matters, the page explains what it changes.

Python 3.10 or newer is required. Several guides use match, X | None syntax, and asyncio.timeout, which is 3.11+.

The smallest thing that runs, to anchor everything above:

main.py
from sillo import SilloApp
app = SilloApp()
@app.get("/")
async def index(request, response):
return response.json({"status": "ok"})
Terminal window
uvicorn main:app --reload

That is a complete ASGI application. Everything else in these guides (validation, the ORM, background work, WebSockets) is something you add to this when you need it, and nothing is required to get here.

Continue with Installation to install Sillo with uv and build your first application.