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.
## 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).