A batteries-included application framework for building structured Rust APIs on top of Axum. Inspired by NestJS's modular architecture, grounded in Rust's type system.
cargo install ironic
ironic new my-api
cd my-api
ironic start- Modular architecture — modules, imports, exports, provider visibility
- Dependency injection — singletons, transients, factories, cycle detection
- HTTP routing — Axum adapter, controllers, parameter extraction
- API versioning — URI prefix, header-based, and media-type versioning strategies
- Request pipeline — middleware, guards, interceptors, error handling
- Parameter pipes — type parsing, validation, and transformation pipelines
- Validation pipes —
ValidationPipewithgardeintegration (#[garde(...)]attributes) - Exception filters — structured error handling with route-level and global filter chains
- Response serialization —
#[derive(Serializable)]with#[exclude]and#[expose(role)]for field-level JSON control - Security middleware — CORS, rate limiting, security headers (HSTS, CSP, X-Content-Type-Options, X-Frame-Options), CSRF protection
- Response compression — gzip, brotli, and zstd via
AxumAdapter::compression() - Procedural macros —
#[derive(Injectable)],#[Module],#[controller],#[get],#[post],#[derive(Serializable)] - Testing utilities — in-process test app, provider overrides, fluent assertions
- CLI — project scaffolding, code generators, doctor command
- OpenAPI — automatic schema generation, Swagger UI
- Integrations — SQLx, SeaORM, Diesel, MongoDB, Redis, JWT, OAuth, gRPC, GraphQL
use ironic::prelude::*;
#[derive(Injectable)]
#[controller("/users")]
struct UsersController {
service: Arc<UsersService>,
}
#[routes]
impl UsersController {
#[get("/:id")]
async fn find_one(&self, #[param] id: Uuid) -> Json<UserResponse> {
Json(self.service.find_one(id).await)
}
}
#[derive(Module)]
#[module(controllers = [UsersController], providers = [UsersService])]
struct UsersModule;
#[ironic::main]
async fn main() {
FrameworkApplication::builder()
.module(AppModule::definition())
.platform(AxumAdapter::new())
.build()
.await
.unwrap()
.listen("127.0.0.1:3000")
.await
.unwrap();
}We welcome contributions! Here's how to get started.
- Find an issue tagged good first issue or help wanted
- Comment on the issue that you're working on it
- Follow the steps below to open a PR
git clone https://github.com/ironic-org/ironic.git
cd ironic
cargo build
cargo testfeat/description # new features
fix/description # bug fixes
chore/description # tooling, CI, deps
docs/description # documentation
refactor/description # code restructuring
Follow Conventional Commits:
feat: add #[ironic::test] proc-macro
fix: resolve DI cycle detection panic
chore: bump axum to 0.8.10
docs: update release workflow guide
- Create a branch from
main:git checkout -b feat/my-feature - Make your changes
- Run checks locally:
cargo build cargo test --all-features cargo clippy --workspace --all-targets --all-features -- -D warnings cargo fmt --all -- --check - Commit and push:
git push origin feat/my-feature - Open a PR against
mainwith:- Clear title matching commit conventions
- Description explaining what and why
Closes #Nto link the issue
- Ensure CI passes on your PR
- Address reviewer feedback with additional commits
| Check | Description |
|---|---|
| Formatting | cargo fmt --check |
| Clippy | cargo clippy -D warnings (all features) |
| Test | cargo test --all-features (stable + nightly) |
| Audit | cargo audit (vulnerability scan) |
| Deny | cargo deny (license + duplicate check) |
| Docs | Build docs site |
| Fuzz | 60s smoke test on nightly |
PRs that violate these rules will not be merged:
- Patterns — follow existing conventions in the codebase
- No comments — code should be self-documenting. Comments only for non-obvious logic
- Small functions — each function should have a single responsibility
- Document all public APIs — every public type, method, and module export needs a doc comment
- Tests required — new features must include tests; bug fixes must include a regression test
All items are checked via the PR template checklist. CI enforces what it can (fmt, clippy, tests); the rest is enforced during review.
If Ironic helps you build something awesome, consider sponsoring the project. Your support covers hosting, tooling, and development time.
Licensed under either of MIT or Apache 2.0 at your option.