Nidus is a modular Rust backend framework for building explicit, production-ready services with typed dependency injection, module graphs, Axum routes, Tower middleware, validation, OpenAPI, observability, testing, and separately installable adapters. It composes Axum, Tower, Tokio, serde, tracing, garde, utoipa, SQLx adapters, cache adapters, and normal Cargo workflows instead of replacing them.
Install the Nidus CLI from crates.io:
cargo install cargo-nidus
cargo nidus new hello-nidus
cd hello-nidus
cargo runDuring local framework development, install the CLI from this checkout:
cargo install --path crates/cargo-nidus
cargo nidus new hello-nidusApplication dependencies stay explicit:
[dependencies]
nidus = { package = "nidus-rs", version = "1.0.16", features = ["http", "config", "openapi", "validation"] }For production observability through the facade:
nidus = { package = "nidus-rs", version = "1.0.16", features = ["observability", "events", "jobs", "otel"] }For embedded dashboard introspection:
nidus = { package = "nidus-rs", version = "1.0.16", features = ["dashboard"] }Official integrations are separate crates:
nidus-sqlx = { version = "1.0.16", features = ["sqlite"] }
nidus-cache = { version = "1.0.16", features = ["moka"] }
nidus-redis = { version = "1.0.16", features = ["health"] }
nidus-kafka = { version = "1.0.16", features = ["health"] }
nidus-jobs-sqlx = { version = "1.0.16", features = ["postgres"] }
nidus-opentelemetry = "1.0.16"
nidus-sentry = "1.0.16"- Use
cargo-nidusforcargo nidus new, route inspection, graph inspection, and OpenAPI generation. - Use
nidus-rsas the application facade. Import it asnidusinCargo.toml. - Enable facade features such as
http,config,openapi,validation,auth,events,jobs,observability, andotelonly when the app needs them. - Add only the data, messaging, durable-job, and telemetry adapter crates the application uses; the facade does not pull them transitively.
- Depend on lower-level crates such as
nidus-coreornidus-httponly when building framework extensions.
Use the prelude at application entrypoints:
use nidus::prelude::*;The prelude is the recommended import because it keeps common app composition types and extension traits in scope:
NidusApplicationExtenablesNidus::create::<AppModule>().- The facade builder supports
.with_router(router)and.build_with_router(router)for composing manual Axum routes with module routes. ApplicationHttpExtremains available for lower-levelNidus::bootstrap::<AppModule>()?.with_router(router)composition.ApiDefaultsObservabilityExtenables.observability(&observability)and observability-aware API defaults when theobservabilityfeature is enabled.
no method named with_routerafterNidus::bootstrap: importApplicationHttpExtornidus::prelude::*; afterNidus::create, call the builder's.with_router(router)before.build().await.no method named listenorno method named into_router: importNidusApplicationExtornidus::prelude::*.no method named observability: importApiDefaultsObservabilityExtornidus::prelude::*.
- Run
cargo nidus new hello-nidusand start the generated server. - Inspect the generated module, controller, and service with
cargo nidus routesandcargo nidus graph. - Add one feature controller or service with
cargo nidus generate. - Add
config,validation, oropenapiwhen the first real route needs it. - Add
nidus-sqlxornidus-cacheonly after the application has a real persistence or cache boundary.
use nidus::prelude::*;
#[controller("/users")]
struct UsersController;
#[routes]
impl UsersController {
#[get("/:id")]
async fn find_one(&self, Path(id): Path<i64>) -> String {
format!("user {id}")
}
}
#[module]
struct AppModule {
controllers: (UsersController,),
}
#[nidus::main]
async fn main() -> nidus::Result<()> {
let app = Nidus::create::<AppModule>()
.build_with_router(UsersController.into_router())
.await?;
app.listen("127.0.0.1:3000").await?;
Ok(())
}- Modules: explicit imports, providers, controllers, and exports.
- Providers: Rust types registered by type, with singleton, transient, request-scoped, lazy, optional, and factory patterns.
- Controllers: Axum-backed route composition with Nidus route metadata.
- Guards and pipes: explicit authorization and validation boundaries.
- Config: typed configuration from JSON, files, pairs, and environment variables.
- OpenAPI: route metadata, schemas, and generated documents.
- Observability: additive production setup for HTTP metrics, traces, events, jobs, lifecycle validation, and official adapter operations.
- Dashboard: optional protected
/nidus/dashboardruntime cockpit with Home, Atlas, Routes, Timeline, Adapters, Settings, JSON APIs, route snapshots, timeline storage, and SSE stream. - Events and jobs: in-process event buses, sync/async queues, and observed runners.
- Testing:
nidus_testing::TestAppfor in-memory request tests and provider overrides.
nidus-http provides opt-in production API defaults for request IDs, request context, health, readiness checks, metrics, CORS, body limits, timeout responses, security headers, structured logging, error envelopes, unmatched-route not_found fallbacks, and OpenTelemetry trace-context helpers. The defaults return normal Axum routers and Tower layers, so applications can replace or reorder the boundary.
Recommended production observability is additive:
use nidus::prelude::*;
let observability = Observability::production("users-api")
.version(env!("CARGO_PKG_VERSION"))
.environment("prod")
.prometheus()
.tracing()
.otel_from_env();
let app = Nidus::create::<AppModule>()
.with_observability(observability.clone())
.build()
.await?;Automatic instrumentation applies where Nidus owns the integration point:
HTTP middleware, ObservedEventBus, ObservedJobRunner, module validation, and
official adapter builders. Raw SQLx queries, raw cache clients, ORMs, queues,
and HTTP clients remain explicit application instrumentation.
The nidus facade stays lean. Redis and SQLx data access, Kafka,
NATS/JetStream, RabbitMQ, SQS, SQLx-backed durable jobs, OpenTelemetry, and
Sentry live in separately installable crates. Each adapter exposes the native
ecosystem client and composes with typed DI, lifecycle, health, observability,
and dashboard events. Shared envelopes and correlation live in
nidus-integrations; broker-specific semantics are not hidden behind a generic
queue API. Delivery is documented as at-most-once or at-least-once where
appropriate, never as universal exactly-once processing.
examples/hello-world: minimal server.examples/openapi: OpenAPI JSON and docs routes.examples/production-api: production middleware defaults.examples/dashboard-api: embedded dashboard runtime cockpit with bearer or local-disabled auth, SQLite storage, metadata-only capture, route snapshots, Atlas graph, Timeline event/job filters, APIs, SSE, and live curl checks.examples/realworld-api: team tasks API with modules, SQLite, validation, OpenAPI, health, observability, request IDs, guards, CORS, limits, timeouts, events, and jobs.examples/sqlx-appandexamples/cache-app: official adapter wiring.examples/integrations-production: runnable Redis, MySQL, CockroachDB, Kafka, NATS/JetStream, RabbitMQ, SQS, durable jobs, OpenTelemetry, and Sentry entrypoints.examples/external-support-desk: copyable external-user support desk API using crates.io-style dependencies, DI, ticket lifecycle routes, API-key auth, request IDs, validation errors, not-found behavior, andnidus-testing.examples/external-commerce: copyable external-user commerce API using crates.io-style dependencies,nidus-sqlxSQLite wiring,nidus-cache, products, carts, inventory, idempotent checkout, health/readiness, metrics, andnidus-testing.
Run an example:
cargo run -p nidus-example-realworld-apiThe external-* examples are standalone Cargo packages with their own
[workspace] tables. Verify them from their folders or with
bash scripts/verify-external-examples.sh; they intentionally do not use local
workspace path dependencies. While preparing an unpublished release, verify the
same examples against temporary local patches:
NIDUS_EXTERNAL_EXAMPLES_LOCAL_PATCH=1 bash scripts/verify-external-examples.shThat mode copies the external examples to a temp directory and appends
temporary [patch.crates-io] entries there only. The checked-in examples stay
copyable crates.io-style manifests.
- Local Markdown docs: docs/
- Generated website source: website/
- GitHub Pages build:
.github/workflows/pages.yml
Build and check the static website locally:
cd website
npm run verifyNidus 1.0.0 established the public crate set. The current release track is 1.0.16, hardening event and module lifecycles, reducing focused observability and configuration-path work, and tightening feature and safe-code boundaries while preserving the established 1.x public APIs.
The fuzz/ package uses cargo-fuzz to compile deterministic fuzz targets for
config parsing, route path normalization, and OpenAPI path normalization:
cargo +nightly fuzz build
cargo +nightly fuzz run route_pathsUse short local runs for development and CI compile checks for release hygiene.
Read CONTRIBUTING.md. Changes should be small, tested, documented, and aligned with Rust ecosystem expectations.
Licensed under either MIT or Apache-2.0.