Quick Navigation
- Who is Reinhardt For?
- Quick Start
- Why Reinhardt?
- Key Features
- Installation
- Getting Started Guide
- Available Components
- Ecosystem
- API Stability
Who is Reinhardt For?
Reinhardt is designed for developers who:
- Know Django/DRF and want the same productivity in Rust
- Use Axum/Actix but miss Django's batteries (ORM, admin, auth, DI)
- Want an integrated Rust web stack without assembling everything from scratch
- Want incremental adoption -- start with just DI or ORM, grow into a full stack later
If you have written ModelSerializer or Depends() before, Reinhardt will feel like home.
Quick Start
# During the RC phase, `cargo install` requires an explicit `--version`
# because pre-releases are not selected by default. Once a stable release
# ships, `cargo install reinhardt-admin-cli` (no flag) will also work.
&&
For a full walkthrough, see the Getting Started Guide.
New to Reinhardt? Start with the default setup first. You can adopt a smaller custom stack later if needed.
Why Reinhardt?
Rust web development is powerful, but it often starts with choosing and wiring together many separate libraries.
Reinhardt takes a different approach: integrated batteries when you want them, composable parts when you don't.
We call this polylithic: many building blocks that still feel like one coherent framework.
Reinhardt brings together the best of four worlds:
| Inspiration | What We Borrowed | What We Improved |
|---|---|---|
| π Django | Batteries-included, ORM, admin | Composable feature flags, type safety |
| π― Django REST | Serializers, ViewSets, permissions | Compile-time validation, zero-cost |
| β‘ FastAPI | DI system, auto OpenAPI | Native performance, no runtime overhead |
| ποΈ SQLAlchemy | QuerySet patterns, relationships | Type-safe queries, compile-time checks |
Result: A framework that's familiar to Python developers, but with Rust's performance and safety guarantees.
β¨ Key Features
- Type-Safe ORM with compile-time validation (reinhardt-query)
- Powerful Serializers with automatic validation (serde + built-in validation)
- FastAPI-Style DI with type-safe dependency injection and caching
- ViewSets for rapid CRUD API development
- Multi-Auth (JWT, Token, Session, Basic) with BaseUser/FullUser traits
- Admin Panel with auto-generated model management interface
- Management Commands for migrations, static files, and more
- GraphQL & WebSocket support for real-time applications
- Pagination, Filtering, Rate Limiting built-in
- Signals for event-driven architecture
See Available Components for complete list and Getting Started for examples.
API Stability
Reinhardt follows a three-phase lifecycle for every crate:
| Phase | What to Expect |
|---|---|
Alpha (0.x.0-alpha.N) |
APIs may change freely. Early adopters welcome. |
RC (0.x.0-rc.N) |
API frozen. Bug fixes only. Safe to build against. |
Stable (0.x.0) |
Full SemVer 2.0 guarantees. |
Current status: All crates are at 0.1.0-rc.28 (Release Candidate).
0.x.y Series Caveat: The RC policy below β API freeze during
rc.*and a 2-week stability window before the first stable release β is followed strictly from1.0.0onward. During the pre-1.0 (0.x.y) period, Reinhardt reserves the right to break RC API compatibility or waive the 2-week stability window when blocking design issues are discovered. Any such exception is documented in the affected crate'sCHANGELOG.mdand is confined to the0.xseries; starting with1.0.0, full SemVer 2.0 guarantees apply without exception. Seedocs/API_STABILITY.mdandinstructions/STABILITY_POLICY.mdfor the complete policy.
What this means for you:
- Public APIs will only change to fix critical bugs -- no new features or additions
- If a critical fix requires an API change, a migration guide is provided
- Naming improvements use deprecation aliases (your existing code keeps compiling)
- Bug fixes are shipped as
rc.2,rc.3, etc. - Stable
0.1.0will be released after a 2-week stability period with no critical issues
For the full stability policy, see API Stability Policy.
Installation
Reinhardt is a modular framework. Choose your starting point:
New here? Start with the default standard setup. Use
fullif you need all features, orminimalfor lightweight APIs.
Default: Standard Setup (Balanced) β οΈ Default Preset
Get a well-balanced feature set with zero configuration:
[]
# Import as 'reinhardt', published as 'reinhardt-web'
# Default enables the "standard" preset (balanced feature set)
= { = "0.1.0-rc.28", = "reinhardt-web" }
Includes: Core, Database (PostgreSQL), REST API (serializers, parsers, pagination, filters, throttling, versioning, metadata, content negotiation), Auth, Middleware (sessions), Pages (WASM Frontend with SSR), Signals
Binary: ~20-30 MB | Compile: Medium
Then use in your code:
use *;
use ;
Option 1: Full-Featured (All Batteries Included)
For projects that need every available component:
[]
= { = "0.1.0-rc.28", = "reinhardt-web", = false, = ["full"] }
Includes: Everything in Standard, plus Admin, GraphQL, WebSockets, Cache, i18n, Mail, Static Files, Storage, and more
Binary: ~50+ MB | Compile: Slower, but everything works out of the box
Option 2: Microservices (Minimal Setup)
Lightweight and fast, perfect for simple APIs:
[]
= { = "0.1.0-rc.28", = "reinhardt-web", = false, = ["minimal"] }
Includes: HTTP, routing, DI, parameter extraction, server
Binary: ~5-10 MB | Compile: Very fast
Option 3: Build Your Custom Stack
Install only the components you need:
[]
# Core components
= "0.1.0-rc.28"
= "0.1.0-rc.28"
# Optional: Database
= "0.1.0-rc.28"
# Optional: Authentication
= "0.1.0-rc.28"
# Optional: REST API features
= "0.1.0-rc.28"
# Optional: Admin panel
= "0.1.0-rc.28"
# Optional: Advanced features
= "0.1.0-rc.28"
= "0.1.0-rc.28"
Note on Crate Naming:
The main Reinhardt crate is published on crates.io as reinhardt-web, but you import it as reinhardt in your code using the package attribute.
π For a complete list of available crates and feature flags, see the Feature Flags Guide.
Getting Started Guide
1. Install Reinhardt Admin Tool
During the RC phase, only release-candidate versions are published to
crates.io, so cargo install requires an explicit --version. The version
shown below is auto-bumped by release-plz on each release. After a stable
release ships, cargo install reinhardt-admin-cli (no flag) will also work.
2. Create a New Project
# Create a RESTful API project (default)
This generates a complete project structure:
my-api/
βββ Cargo.toml
βββ src/
β βββ lib.rs
β βββ config.rs
β βββ apps.rs
β βββ config/
β β βββ settings.rs
β β βββ settings/
β β β βββ base.rs
β β β βββ local.rs
β β β βββ staging.rs
β β β βββ production.rs
β β βββ urls.rs
β β βββ apps.rs
β βββ bin/
β βββ manage.rs
βββ README.md
Alternative: Create a reinhardt-pages Project (WASM + SSR)
For a modern WASM-based frontend with SSR:
# Create a pages project
# Install WASM build tools (first time only)
# Build WASM and start development server
# Visit http://127.0.0.1:8000/
3. Run the Development Server
# Using the manage command
# Server will start at http://127.0.0.1:8000
Auto-Reload Support:
The development server reloads automatically on file changes:
Edit any Rust source file (server-side or wasm-side) and the bundle
plus the server are rebuilt in place. Pass --noreload to disable
auto-reload entirely, or --no-wasm-rebuild to keep server reload
but manage the wasm build yourself.
4. Create Your First App
# Create a RESTful API app (default)
# Or explicitly specify type
# Create a Pages app (WASM + SSR)
This creates an app structure β the layout depends on the template:
RESTful app (--with-rest, default):
users/
βββ lib.rs
βββ models.rs
βββ models/
βββ views.rs
βββ views/
βββ serializers.rs
βββ serializers/
βββ admin.rs
βββ admin/
βββ urls.rs
βββ tests.rs
βββ tests/
Pages app (--with-pages, WASM + SSR):
dashboard/
βββ lib.rs
βββ models.rs
βββ models/
βββ views.rs
βββ serializers.rs
βββ serializers/
βββ admin.rs
βββ server.rs
βββ server/
β βββ server_fn.rs
βββ client.rs
βββ client/
β βββ components.rs
βββ shared.rs
βββ shared/
β βββ errors.rs
β βββ types.rs
βββ urls.rs
βββ urls/
β βββ server_urls.rs
β βββ client_urls.rs
β βββ ws_urls.rs
βββ tests.rs
βββ tests/
5. Register Routes
Edit your app's urls.rs. urls.rs plays two roles: it declares the URL
submodules of the app (via pub mod ...;) and aggregates them into a
single url_patterns (or server_url_patterns / unified_url_patterns) entry
point that src/config/urls.rs mounts:
// users/urls.rs
//
// 1. Module declarations for sub-URL files (optional, for larger apps):
// 2. Aggregator β the single entry point mounted from src/config/urls.rs.
use url_patterns;
use ServerRouter;
use crateInstalledApp;
The #[url_patterns] attribute registers this router with the framework for
automatic discovery. For Pages apps, use mode = unified and return
UnifiedRouter instead (see the generated urls/{server,client,ws}_urls.rs
submodules).
Include in src/config/urls.rs:
// src/config/urls.rs
use *;
use routes;
The #[routes] attribute macro automatically registers this function with the
framework for discovery via the inventory crate.
Note: The reinhardt::prelude includes commonly used types. Key exports include:
Always Available:
- Core routing and views:
Router,DefaultRouter,ServerRouter,View,ListView,DetailView - ViewSets:
ViewSet,ModelViewSet,ReadOnlyModelViewSet - HTTP:
StatusCode
Feature-Dependent:
corefeature:Request,Response,Handler,Middleware, Signals (post_save,pre_save, etc.)databasefeature:Model,DatabaseConnection,F,Q,Transaction,atomic, Database functions (Concat,Upper,Lower,Now,CurrentDate), Window functions (Window,RowNumber,Rank,DenseRank), Constraints (UniqueConstraint,CheckConstraint,ForeignKeyConstraint)authfeature:BaseUser,FullUser,PermissionsMixin,BaseUserManager,Argon2Hasher,GroupManager,CreateGroupData,Permission,ObjectPermission,ObjectPermissionManagerminimal,standard, ordifeatures:Body,Cookie,Header,Json,Path,Queryrestfeature: Serializers, Parsers, Pagination, Throttling, Versioningadminfeature: Admin panel componentscachefeature:Cache,InMemoryCachesessionsfeature:Session,AuthenticationMiddleware
For a complete list, see Feature Flags Guide.
For a complete step-by-step guide, see Getting Started.
π Learn by Example
With Database
Configure database in settings/base.toml:
= true
= "your-secret-key-for-development"
[]
= "postgresql"
= "localhost"
= 5432
= "mydb"
= "postgres"
= "postgres"
Settings are automatically loaded in src/config/settings.rs:
// src/config/settings.rs
use *;
// Compose built-in settings fragments with | β field names are inferred from type names
// (e.g., CoreSettings β core, AuthSettings β auth, DatabaseSettings β database)
;
The | syntax composes settings fragments into ProjectSettings. Each type must be a #[settings(fragment = true, ...)] struct. Built-in fragments:
CoreSettingsβdebug,secret_key,language_code,time_zone,allowed_hostsAuthSettingsβjwt_secret,token_expiry,password_hashersDatabaseSettingsβengine,host,port,name,user,password
Add project-specific fragments with explicit field names using key: Type syntax:
;
See Settings Documentation for more details.
Defining a User Model:
Define your own user model with #[user(...)] + #[model(...)]. These two
attribute macros cooperate: #[user] implements the auth traits (BaseUser,
PermissionsMixin, AuthIdentity, and optionally FullUser) on top of a
normal Reinhardt model:
// users/models.rs
use *;
use Argon2Hasher;
#[user] arguments:
hasher(required) β password hasher type (e.g.,Argon2Hasher)username_field(required) β name of the field used as the usernamefull = true(optional) β also implementFullUser(email, first_name, last_name, is_staff, date_joined)
Model Attribute Macro:
The #[model(...)] attribute automatically generates:
- Implementation of the
Modeltrait (includes#[derive(Model)]functionality) - Type-safe field accessors:
User::field_email(),User::field_username(), etc. - Global model registry registration
- Support for composite primary keys
Note: When using #[model(...)], you do NOT need to add #[derive(Model)] separately,
as it is automatically applied by the #[model(...)] attribute.
Field Attributes:
#[field(primary_key = true)]- Mark as primary key#[field(max_length = 255)]- Set maximum length for string fields#[field(default = value)]- Set default value#[field(auto_now_add = true)]- Auto-populate timestamp on creation#[field(auto_now = true)]- Auto-update timestamp on save#[field(null = true)]- Allow NULL values#[field(unique = true)]- Enforce uniqueness constraint
For a complete list of field attributes, see the Field Attributes Guide.
The generated field accessors enable type-safe field references in queries:
// Generated by #[model(...)] for the User struct above:
Advanced Query Examples:
use *;
use crateUser;
// Django-style F/Q object queries with type-safe field references
async
// Transaction support
async
Note: Reinhardt uses reinhardt-query for SQL operations. The #[model(...)] attribute automatically generates Model trait implementations, type-safe field accessors, and global model registry registration.
Register in src/config/apps.rs:
// src/config/apps.rs
use installed_apps;
// The installed_apps! macro generates:
// - An enum InstalledApp with variants for each app
// - Implementation of conversion traits (From, Into, Display)
// - A registry for app configuration and discovery
//
// Note: Unlike Django's INSTALLED_APPS, this macro is for user apps only.
// Built-in framework features (auth, sessions, admin, etc.) are enabled via
// Cargo feature flags, not through installed_apps!.
//
// Example:
// [dependencies]
// reinhardt = { version = "0.1", features = ["auth", "sessions", "admin"] }
//
// This enables:
// - Automatic app discovery for migrations, admin panel, etc.
// - Type-safe app references throughout your code
// - Centralized app configuration
installed_apps!
With Authentication
Reinhardt provides Django-style user models and permission primitives. You
bring your own user struct (defined with #[user(...)] + #[model(...)] as
shown in the previous section); the framework layers auth traits, a
password-management workflow, groups, and object-level permissions on top.
Two entry points for user data:
| Need | Use |
|---|---|
| ORM queries on users (filter/annotate/aggregate) | User::objects() (from #[model]) |
| User lifecycle: create/password-hashing/superuser | A BaseUserManager<User> implementation |
| Groups | GroupManager |
| Object-level permissions | ObjectPermissionManager |
User::objects()is not a shortcut to a manager β it is theQuerySetentry point from theModeltrait. Manager types (BaseUserManager<User>for the user lifecycle,GroupManager,ObjectPermissionManager) are constructed directly via::new().
User lifecycle example:
For a custom user, implement BaseUserManager<User> (see
reinhardt::auth::BaseUserManager). The signature required is:
use HashMap;
use async_trait;
use ;
use *;
use Value;
use crateUser;
Then:
let mut users = new;
let alice = users
.create_user
.await?;
Groups and object-level permissions:
GroupManager and ObjectPermissionManager are always available and are
instantiated directly:
use ;
let mut groups = new;
let editors = groups
.create_group
.await?;
let mut perms = new;
perms.grant_permission.await;
Use JWT authentication in your app's views/profile.rs:
// users/views/profile.rs
use ;
use AuthUser;
use crateUser;
// JwtAuthMiddleware must be registered in urls.rs to populate AuthState in request extensions
pub async
Dependency Injection
Reinhardt ships a FastAPI-inspired, async-first dependency injection (DI)
system in the reinhardt-di crate. It is type-safe, scope-aware (singleton /
request / transient), composable (dependencies can depend on other
dependencies), and registered at compile time via the
inventory crate so that there is no
runtime reflection or startup discovery cost.
Three primitives drive everyday use:
#[injectable]β turn a struct into an injectable service.#[injectable_factory]β register an async function as a factory for types you cannot annotate yourself (foreign types, trait objects, connection handles built from settings).#[inject]withDepends<T>β receive dependencies in a handler (or another injectable) without wiring anything by hand.
1. #[injectable] β struct-level injection
Apply #[injectable] to any struct whose fields are themselves injectable.
Non-injected fields are marked with #[no_inject] and must implement
Default (or be supplied via the generated builder):
use injectable;
// optional: singleton (default) | request | transient
#[injectable] generates an impl Injectable for Config and a compile-time
registration entry (via inventory::submit!) so the type resolves from
InjectionContext automatically.
2. #[injectable_factory] β the pseudo orphan rule
Rust's orphan rule forbids impl Injectable for SomeForeignType. For those
cases β database connections, Arc<dyn Trait>, third-party handles β Reinhardt
offers #[injectable_factory]. You write an async function whose return type
is the type to register; the macro wraps it, submits an inventory entry, and
hands the returned value to the DI container:
use DatabaseConnection;
use ;
async
Every parameter of an #[injectable_factory] function must be annotated
with #[inject]. There is no way to pass runtime arguments; factories only
compose over other injectables.
The pseudo orphan rule. To prevent user factories from silently shadowing
framework-owned types (e.g., reinhardt_di::InjectionContext, routers,
middleware bindings), Reinhardt validates every registered factory at startup.
If the return type's fully-qualified name begins with a
framework-reserved crate prefix (reinhardt::, reinhardt_di::, reinhardt_http::,
β¦ 37 prefixes total), registration is rejected unless the factory itself lives
inside that crate. This emulates the orphan rule across the DI boundary: foreign
types are fair game, framework types are not. The validator lives in
crates/reinhardt-di/src/validation.rs
(check_framework_type_override, lines 51β129).
3. #[inject] + Depends<T> in handlers
Use #[inject] on a handler parameter to have the DI container resolve it
before the handler runs. Wrap the requested type in Depends<T> so that
caching and scope are honoured:
use ;
use Depends;
use DatabaseConnection;
use Path;
use crateUser;
pub async
Caching. Within a scope boundary, resolving the same Depends<T> twice
returns the same instance. Opt out per-call with #[inject(cache = false)]:
pub async
Manual impl Injectable
When neither macro fits (generic bounds the macro cannot infer, hand-written
builders, conditional registration), implement Injectable directly:
use async_trait;
use ;
For the full DI reference, see the reinhardt-di crate
documentation.
Endpoint Definition
Reinhardt uses HTTP method decorators to define endpoints:
HTTP Method Decorators
Use #[get], #[post], #[put], #[delete] to define routes:
use ;
use json;
pub async
pub async
Features:
- Compile-time path validation
- Concise syntax
- Automatic HTTP method binding
- Support for dependency injection via
#[inject]
Using Dependency Injection
Combine HTTP method decorators with #[inject] for automatic dependency injection:
use ;
use Path;
use Depends;
use DatabaseConnection;
use crateUser;
pub async
Dependency Injection Features:
- Automatic dependency injection via
#[inject]attribute - Cache control with
#[inject(cache = false)] - FastAPI-inspired dependency injection system
- Works seamlessly with HTTP method decorators
Result Type:
All view functions use ViewResult<T> as the return type:
use ViewResult; // Pre-defined result type
With Parameter Extraction
In your app's views/user.rs:
// users/views/user.rs
use ;
use ;
use Depends;
use DatabaseConnection;
use crateUser;
use Deserialize;
pub async
Register route with path parameter in urls.rs:
// users/urls.rs
use ServerRouter;
use views;
With Serializers and Validation
In your app's serializers/user.rs:
// users/serializers/user.rs
use ;
use Validate;
In your app's views/user.rs:
// users/views/user.rs
use ;
use Json;
use Validated;
use Depends;
use DatabaseConnection;
use crateUser;
use crate;
pub async
Adoption Paths
| Your Goal | Start Here |
|---|---|
| Full-stack REST API | Getting Started Guide |
| Full-stack with Pages (WASM + SSR) | Twitter Demo |
| Lightweight DI-focused API | Minimal Installation |
Standalone DI for existing Axum apps is planned for a future release. See Discussions for updates.
Available Components
Reinhardt offers modular components you can mix and match:
| Component | Crate Name | Features |
|---|---|---|
| Core | ||
| Core Types | reinhardt-core |
Core traits, types, macros (Model, endpoint) |
| HTTP & Routing | reinhardt-http |
Request/Response, HTTP handling |
| URL Routing | reinhardt-urls |
Function-based and class-based routes |
| Server | reinhardt-server |
HTTP server implementation |
| Dispatch | reinhardt-dispatch |
HTTP request dispatching, handler composition |
| Configuration | reinhardt-conf |
Settings management, environment loading |
| Commands | reinhardt-commands |
Management CLI tools (startproject, etc.) |
| Shortcuts | reinhardt-shortcuts |
Common utility functions |
| Database | ||
| ORM | reinhardt-db |
reinhardt-query integration |
| Authentication | ||
| Auth | reinhardt-auth |
JWT, Token, Session, Basic auth, User models |
| REST API | ||
| Serializers | reinhardt-rest |
built-in serialization and validation, ViewSets |
| Forms | ||
| Forms | reinhardt-forms |
Form handling and validation |
| Advanced | ||
| Admin Panel | reinhardt-admin |
Django-style admin interface |
| Plugin System | reinhardt-dentdelion |
Static & WASM plugin support, CLI management |
| Background Tasks | reinhardt-tasks |
Task queues (Redis, RabbitMQ, SQLite) |
| GraphQL | reinhardt-graphql |
Schema generation, subscriptions |
| WebSockets | reinhardt-websockets |
Real-time communication |
| i18n | reinhardt-i18n |
Multi-language support |
reinhardt-mail |
Email sending and templating | |
| gRPC | reinhardt-grpc |
gRPC services, protobuf types |
| Deep Link | reinhardt-deeplink |
iOS Universal Links, Android App Links |
| Middleware | ||
| Middleware | reinhardt-middleware |
HTTP middleware components, CORS, security |
| Testing | ||
| Test Utilities | reinhardt-test |
Testing helpers, fixtures, TestContainers |
| Test Kit | reinhardt-testkit |
Higher-level test abstractions and utilities |
For detailed feature flags within each crate, see the Feature Flags Guide.
Ecosystem
| Project | Status | Description |
|---|---|---|
| reinhardt-cloud | WIP | Kubernetes operator & CLI for deploying Reinhardt apps |
Dog-fooding in progress: We are actively developing reinhardt-cloud as the deployment infrastructure for Reinhardt applications, and using it to deploy reinhardt-web itself. As a work-in-progress project, APIs and features may change significantly.
Documentation
- π Getting Started Guide - Step-by-step tutorial for beginners
- ποΈ Feature Flags Guide - Optimize your build with granular feature control
- π API Reference (Coming soon)
- π Tutorials - Learn by building real applications
For AI Assistants: See CLAUDE.md for project-specific coding standards, testing guidelines, and development conventions.
π¬ Getting Help
Reinhardt is a community-driven project. Here's where you can get help:
- π¬ Discord: Join our Discord server for real-time chat (coming soon)
- π GitHub Discussions: Ask questions and share ideas
- π Issues: Report bugs
- π Documentation: Read the guides
Before asking, please check:
- β Getting Started Guide
- β Examples
- β Existing GitHub Issues and Discussions
π€ Contributing
We love contributions! Please read our Contributing Guide to get started.
Quick links:
β Star History
Copyright
Copyright Β© 2026 Tachyon Inc. All rights reserved.
Developed by Tachyon Inc.
License
This project is licensed under the BSD 3-Clause License.
Third-Party Attribution
This project is inspired by:
- Django (BSD 3-Clause License)
- Django REST Framework (BSD 3-Clause License)
- FastAPI (MIT License)
- SQLAlchemy (MIT License)
See THIRD-PARTY-NOTICES for full attribution.
Note: This project is not affiliated with or endorsed by the Django Software Foundation, Encode OSS Ltd., SebastiΓ‘n RamΓrez (FastAPI author), or Michael Bayer (SQLAlchemy author).