Nori Framework¶
The async Python framework where server-rendered pages and JSON APIs are first-class peers.
What is Nori?¶
Nori is an async web framework built on Starlette and Tortoise ORM, designed for apps that live in both shapes at once — server-rendered pages and JSON APIs as first-class peers, not one bolted onto the other.
This is the shape Nori was built for:
- A SaaS dashboard with an HTMX UI and a JSON endpoint for the mobile client
- An admin panel and a public API for third-party integrations
- A marketing site that also handles webhooks and background jobs
Everything you need to build that app lives in the core. Auth, validation, ORM, queues, WebSockets, CSRF, rate limiting, testing — one of each, integrated. No stitching.
Quick Start¶
Platform: Nori is tested on Linux and macOS. Windows users should run inside WSL2. See Installation for full prerequisites.
# Install
curl -fsSL https://nori.sembei.mx/install.py | python3 - my-project
cd my-project
source .venv/bin/activate
# Edit rootsystem/application/.env if you need MySQL/Postgres (defaults to SQLite)
# Initialize the database and start the dev server
python3 nori.py migrate:init
python3 nori.py serve
Visit http://localhost:8000 to see the welcome page.
Create Your First Feature¶
Nori follows a 7-step protocol for adding features. Generators give you skeletons; you fill in the domain-specific parts in the editor between commands.
# 0. First-time setup (once per project): generate framework + user tables for your engine
python3 nori.py migrate:init
# 1. Generate the model skeleton, then EDIT IT to add your fields
python3 nori.py make:model Article
# → opens rootsystem/application/models/article.py with id + name + timestamps.
# Replace the `name` placeholder with your actual columns
# (title, body, slug, published_at, etc.) before continuing.
# 2. Register the model in rootsystem/application/models/__init__.py
# (the CLI prints the exact import + register_model call you need to paste)
# 3. Create and run the migration (now reflects your real schema)
python3 nori.py migrate:make create_articles
python3 nori.py migrate:upgrade
# 4. Generate the controller skeleton, then EDIT IT to add your handlers
python3 nori.py make:controller Article
# → opens rootsystem/application/modules/article.py with placeholder methods.
# Replace them with your real index/show/store/update/destroy logic.
# 5. Define routes in rootsystem/application/routes.py
# (explicit Route() entries with methods=[...] and dot-notation names)
# 6. Create Jinja templates in rootsystem/templates/articles/
# (e.g. index.html, show.html — extend base.html, use {{ csrf_field(...) }})
# 7. Run tests
pip install -r requirements-dev.txt
DEBUG=true pytest tests/
For a full walkthrough with code examples — model fields, controller methods, templates, seeders — see the Tutorial. Builds a working blog in 5 minutes.
Key Features¶
- Session Auth + JWT — Login, roles, granular permissions (ACL), brute-force protection, JWT revocation, session permissions TTL
- OAuth2 — Google (OpenID Connect + PKCE) and GitHub drivers included
- Declarative Validation — 19 built-in rules with pipe syntax:
'required|email|max:255|url|date|confirmed|nullable' - Form Re-population —
flash_old()+{{ old('field') }}Jinja helper preserves user input across validation errors, with sensitive fields auto-excluded - Multi-Driver Services — Storage, Email, Search, Cache with pluggable backends and memory backend guards
- Background Tasks — Volatile (
background()) and persistent job queues (push()) with database and Redis drivers - WebSockets — Handler base classes with session/JWT auth
- Collections — Chainable
NoriCollectionwith filtering, sorting, grouping, and aggregation - Security by Default — CSRF, security headers, magic byte upload verification, protected fields
- Observability Hook —
bootstrap.pyruns before Starlette/Tortoise so Sentry, OTel, or Datadog SDKs initialize at the right time - CLI + Plugin System — Built-in generators, async
shellREPL with models pre-loaded, plus custom commands incommands/that survive framework updates - Testing Utilities — Test client, model factories, session auth helpers, and assertion helpers
- Framework Updates —
python3 nori.py framework:updatepulls the latest core from GitHub. Splitrequirements.nori.txtkeeps framework deps in sync without touching yourrequirements.txt.
Documentation¶
| Section | Description |
|---|---|
| Architecture | Request lifecycle, middleware stack, dependency injection |
| Authentication | Sessions, JWT, OAuth2, ACL, brute-force protection |
| Controllers | Request handling, @inject(), security decorators |
| Routing | Route definitions, mounts, dot-notation names |
| Database | Tortoise ORM, migrations, soft deletes, tree structures |
| Templates | Jinja2 views, layouts, CSRF fields |
| Forms & Validation | Declarative rules, file validation, error handling |
| Collections | Chainable filtering, sorting, grouping, aggregation |
| Security | CSRF, headers, rate limiting, upload verification, JWT |
| Services | Storage, email, search, audit logging with driver pattern |
| Caching | Cache drivers and usage patterns |
| Background Tasks | Volatile tasks and persistent job queues |
| WebSockets | Handler base classes with session/JWT auth |
| Flash Messages | Session-based flash notifications |
| Logging | Request ID tracing and structured logging |
| Deployment | Gunicorn, Apache/Nginx, Docker, sizing guide |
| Testing | Test client, model factories, auth helpers, assertions |
| CLI Reference | All commands, plugin system for custom commands |
| Philosophy | Design principles and framework goals |
| Roadmap | Planned features and development direction |
Built by Sembei