NestRS

The Rust framework for modular, scalable backends.
You write the business logic; the framework carries the rest — modules, decorators and dependency injection over a native core.
~25× less memory · ~23× faster cold starts · ×4 the throughput of NestJS, core for core — measured on a byte-identical contract, reproducible from the repo.

crates.io docs.rs GitHub stars MIT License PRs welcome

## What it is You write business logic; the framework carries the rest — authn, authz, row-level tenant filtering, per-field masking, transactions, discovery, and lifecycle. Those concerns are transparent to your code and verified at boot, not left to review discipline. A full authenticated, tenant-scoped, transactional, field-masked CRUD resource is an empty `impl` block: ```rust #[controller(path = "/orgs")] #[use_guards(AuthnGuard, AuthzGuard)] pub struct OrgsController { #[inject] svc: Arc, } #[crud(service = svc, entity = OrgEntity, output = Org, create = CreateOrg, update = UpdateOrg)] impl OrgsController {} ``` The differentiator is **structural multi-tenant isolation you cannot forget**: row-level filtering, response masking, and transactions become non-optional the moment the security modules are imported. A feature opts *out* by not importing them. In NestJS, Spring, Rails, axum, or Loco, tenant filtering is discipline — a scope you remember, a middleware you apply, a review comment. In NestRS it is structural: the data layer applies it from the caller's ability, and an operation with no declared access posture is refused — at compile time on GraphQL, at boot on HTTP. MCP gets the same guarantee across the *whole* protocol, not `tools/call` alone: scope, ability and transaction reach `prompts/get`, `resources/read`, completion and the `tasks/*` trio, so a `Repo`-backed prompt is row-filtered exactly like a controller. The numbers behind the tagline — against the same hello-world service in NestJS 11, idiomatic on both sides, byte-identical HTTP contract, conformance-gated: NestRS runs in **~25× less memory** (single-digit MB against ~200 MB), cold-starts **~23× faster** (milliseconds against near half a second), and — core for core, each server pinned to a single CPU — serves **×4.2 the throughput of NestJS on Express** (its default) — **×2.5 its best case, Fastify** — with **p99 latency cut to a third**. Scaling out changes nothing: Node adds ~200 MB of process per core; one NestRS binary takes every core in a single single-digit-MB process. Where the Express service needs three boxes, one NestRS binary carries the load. Those figures come from a **4-core / 8 GB Docker VM** — virtualized, so they are a floor, not a ceiling. The harness lives in [`bench/`](bench/) — `cd bench && just bench` reproduces every figure on your own hardware. Try it on your machine: ```bash cargo install --locked nest-rs-cli nestrs new hello && cd hello nestrs run dev # → Hello World on :3000 ``` Adding NestRS to a crate you already have is **one dependency**. Every capability — `http`, `graphql`, `seaorm`, `ws`, `mcp`, `queue`, `schedule`, … — is a feature of the umbrella, and a feature you leave off is code you never compile. No decorator ever asks you to declare a second crate: ```bash cargo add nest-rs --features http,seaorm ``` → [Why not axum?](https://nestrs.dev/why-not-axum/) · [Coming from NestJS](https://nestrs.dev/coming-from-nestjs/) · [Why NestRS](https://nestrs.dev/why/) ## What ships Every concern below is a module you import and a Cargo feature you can leave off — a headless worker compiles no HTTP stack. Each has a reference section on [nestrs.dev](https://nestrs.dev). | Concern | What ships | |---|---| | **Transports** | HTTP controllers with versioning, extractors, uploads, streaming · OpenAPI 3 + Swagger UI from the route table · GraphQL with dataloaders, subscriptions and federation · WebSocket gateways · MCP tools, prompts and resources | | **Data** | SeaORM entities, `Repo`, ambient transactions, pagination, migrations, seeding · S3-compatible object storage | | **Security** | JWT on EdDSA keys, OAuth2 with PKCE, Argon2id passwords, social login · abilities, row-level filtering, per-field masking, one policy across every transport | | **Background work** | Redis-backed queues with retries, cron schedules, a typed in-process event bus | | **Platform** | Typed config with an `.env` cascade · liveness/readiness/startup probes · rate limiting · OpenTelemetry logs, traces, metrics · `Server-Timing` | | **Tooling** | The `nestrs` CLI — scaffold, generate a feature or an adapter, run, migrate · an in-process test harness booting the real DI graph | ## What holds it up Claims a clone of this repository lets you check: - **66 decorators**, one per integration contract, each expanding to plain Rust you can print with `cargo expand` — the index is on [nestrs.dev/decorators](https://nestrs.dev/decorators/). - **1,800+ tests** across the framework workspace, with the end-to-end suites running against live Postgres, Redis and S3 rather than mocks — the dev container brings all three up before you get a shell. - **Conformance joins** — the families the framework declares (decorator pairs, `for_root` seams, the `warn`-level events that record a denial) are derived from the source and joined against the suites covering them, so a member no test names fails the suite ([`crates/nest-rs-conformance/`](crates/nest-rs-conformance/)). - **Documentation gated against the code** — 120+ pages, and a linter reading the framework's own source for config key tables, trait signatures, version pins and the imports a snippet needs to compile ([`docs/scripts/lint-docs.mjs`](docs/scripts/lint-docs.mjs)). ## Stability **NestRS is stable and ready for production.** The public API is frozen for the current major: breaking changes wait for the next one. Every `nest-rs-*` crate publishes at the same version in lockstep, so one NestRS version names exactly one compatible resolution — down to the third-party crates that surface in your own signatures (`poem`, `sea-orm`, `async-graphql`, `rmcp`, `schemars`), whose majors are tied to the NestRS major and frozen for the whole line. Coming from the previous major? [`CHANGELOG.md`](CHANGELOG.md) lists what moved: an edge is now **two** decorators — `#[resolver]` / `#[mcp]` on the struct, `#[operations]` / `#[tools]` on the impl; a guard bound where its check never runs no longer compiles; `McpModule::for_root` takes one value; a WebSocket message declares its posture; and an auto-resolved HasMany relation is a Relay `Connection` rather than a capped `Vec`. ## Documentation **Using NestRS?** Head to **[nestrs.dev](https://nestrs.dev)** — getting started, tutorial, [why NestRS](https://nestrs.dev/why/), the [axum comparison](https://nestrs.dev/why-not-axum/), and one section per capability crate. **Contributing to the framework?** This README is your entry point. For design rules and conventions, read [`CLAUDE.md`](CLAUDE.md) and [`CONTRIBUTING.md`](CONTRIBUTING.md). ## Contributing Anyone who can clone the repo can iterate on the framework — the dev container brings up Rust, Postgres and Redis in one step. ### Get the dev container running 1. Install [Docker](https://docs.docker.com/get-docker/) and the VS Code [Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension. 2. Open the repo in VS Code and accept **Reopen in Container**. 3. `cd demo && nestrs run dev api` — the main Publish API on `http://localhost:3002` (run `nestrs run db up` first). The container provisions the Rust toolchain and dev tooling (`just`, `bacon`, `cargo-nextest`, …), and brings up **Postgres** and **Redis** beside it with `NESTRS_SEAORM__URL` / `NESTRS_REDIS__URL` already pointed at them. `nestrs run dev` runs under `bacon` — every save triggers an incremental rebuild and a restart. The runnable apps live in their own workspace under [`demo/`](demo/) — `cd demo` first; that directory is where `nestrs run`, the `.env` cascade, and the database/test recipes resolve. > Prefer a local toolchain? See [Getting started → Scaffold and start](https://nestrs.dev/getting-started/#scaffold-and-start). ### Project layout **Two Cargo workspaces**, split along the framework/product line. ``` nestrs/ ├─ crates/ the framework — nest-rs (the umbrella apps install) │ │ over one nest-rs-* compilation unit per capability │ ├─ nest-rs-core/ IoC container, modules, DI, bootstrap │ ├─ nest-rs-http/ REST controllers & routing │ └─ … (members = ["crates/*"]) ├─ docs/ the nestrs.dev site (Astro Starlight) └─ demo/ the product — its own workspace, consumes the framework ├─ apps/ one runnable binary each (the Publish workspace) │ ├─ auth/ OAuth2 / JWT token issuer │ ├─ api/ REST + GraphQL + OpenAPI, persisted & authorized │ ├─ assistant/ Model Context Protocol server │ ├─ live/ real-time WebSocket gateway │ └─ worker/ background jobs & scheduling (headless) ├─ crates/ │ ├─ features/ product features — port + adapters (users, posts, authn, …) │ ├─ migrations/ shared-database SeaORM migrations (CLI) │ └─ seed/ shared-database demo data (CLI) ├─ Justfile, db.just, test.just, .env*, Dockerfile └─ (members = ["apps/*", "crates/*"]) ``` The **`demo/`** workspace references the framework by relative path — one workspace dependency, `nest-rs = { path = "../crates/nest-rs", features = [ …] }`, exactly the shape a real app has — so it builds against the live framework source. You `cd demo` and drive it as if it were the app's own repository — see [`demo/README.md`](demo/README.md) for running the apps, the command table, the Publish map, and Docker. - **`crates/nest-rs-*/`** — the framework: generic, product-agnostic building blocks, reached through the `nest-rs` umbrella rather than named one by one. - **`demo/apps//`** — `main.rs` + `module.rs` listing the edge modules the binary serves. - **`demo/crates/features/`** — the product's vertical slices; apps import the edges they serve. Adding an app means a directory under `demo/apps/`; a new feature means a folder under `demo/crates/features/src/`; a new framework capability means a `nest-rs-*` crate under `crates/`. The **hello** and **blog** layouts are generated on demand by `nestrs new` rather than checked in, so they never drift from the framework — see [Getting started](https://nestrs.dev/getting-started/) and the [tutorial](https://nestrs.dev/tutorial/). ### Running the apps Everything runnable lives in [`demo/`](demo/) — `cd demo` first, then `nestrs run` (no args lists every recipe). The full command table, the Publish app map, and the Docker build are documented in [`demo/README.md`](demo/README.md). ## Community & contributing NestRS is stable and actively developed — contributors shape where it goes next, and you don't have to write Rust to help. - 💬 **Ask a question, propose an idea, or just say hi** in [Discussions](https://github.com/YV17labs/NestRS/discussions). - 🐛 **Report a bug or request a feature** through [issues](https://github.com/YV17labs/NestRS/issues/new/choose). - 🌱 **Pick up a** [`good first issue`](https://github.com/YV17labs/NestRS/labels/good%20first%20issue) — [CONTRIBUTING.md](CONTRIBUTING.md) is the short path from idea to merged PR. - 🗺️ **See what just shipped** in the [changelog](CHANGELOG.md). - 🔒 **Found a vulnerability?** Follow [SECURITY.md](SECURITY.md) — please don't open a public issue for it. If NestRS is useful to you, a ⭐ helps other Rust teams find it. ## License MIT — see [LICENSE](LICENSE).