Release notes
Navree 0.1.0, the first release: what each module ships, the CLI, the reference CRM and the benchmark, and the known limitations you may run into.
On this page
Navree 0.1.0
0.1.0 is Navree's first release. It contains 28 crates: the kernel, the shared contracts and 23 module crates, the navree facade that re-exports them, the attribute macros and the navree CLI. All of them share one version number. The repository also holds a reference CRM built on Navree and a benchmark against fourteen other framework set-ups.
Navree was developed under the working names Keel and, briefly, Navis. You may still meet those names in the repository's design notes from that time.
What's included
Foundation
navree-kernel: the module graph, a type-keyed dependency-injection container with singleton, request and transient scopes, lifecycle hooks, graceful shutdown and the command runner behindserve,migrateand every other command. The graph is validated before anything is constructed, andcheck --graphprints it.navree-macros:#[module],#[injectable],#[controller], the route attributes (#[get],#[post],#[put],#[patch],#[delete]) and the helper attributes for access, throttling, timeouts, transactions, audit actions and OpenAPI metadata. A route without an access declaration doesn't compile.navree-contracts: the small shared traits and types that let modules cooperate without depending on each other:Secret<T>,RequestId,Principal, jobs and dispatchers, sinks for audit and events,BroadcasterandClock.navree-config: typed configuration from.env, TOML files andAPP_*environment variables, validated at boot, with secrets redacted in logs and errors.navree-log: a tracing subscriber with pretty or JSON output, field redaction, per-target levels and rotating log files.
HTTP
navree-http: Axum integration with a default pipeline (request ids, client IP resolution through trusted proxies, panic catching, timeouts, security headers, compression, a per-IP rate limit, body limits, maintenance mode), controllers, deny-by-default route access, per-route throttles, signed URLs, CORS and errors in the NestJS format ({statusCode, message, error}, validation failures as 400 witherrors).navree-validation:Valid<Json<T>>,Valid<Query<T>>and friends on garde, with class-validator-style messages and asyncuniqueandexistsrules.navree-api: an OpenAPI 3.1 document built from route metadata at/api/openapi.json, a docs UI at/api/docs,openapi:export, and API resource helpers.navree-session: encrypted session cookies with memory and database stores, and CSRF protection. It is optional; the CRM and new apps don't use it.
Data
navree-db: SeaORM integration with a unit of work per request (a transaction that commits when the response succeeds),Repowith change events, per-module migration sets, seeders, model factories, pagination and themigrate,migrate:rollback,migrate:fresh,migrate:statusanddb:seedcommands. SQLite by default; PostgreSQL with thepostgresfeature.navree-cache: a memory cache store on moka withremember, tags, stale-while-revalidate and atomic locks.
Security
navree-auth: NestJS-style authentication with 15-minute JWT access tokens and 30-day rotating refresh tokens with reuse detection, Passport-style strategies,CurrentUser, registration, password change and reset, email verification, TOTP two-factor authentication with recovery codes, and login throttling.navree-access: roles, permissions and CASL-compatible abilities, record checks for#[can(.., from = "id")]routes, SQL list filters withAccessible, the abilities endpoint for front ends, management routes and theaccess:role,access:grantandaccess:explaincommands.navree-crypto: AES-256-GCM encryption with key rotation, Argon2id password hashing on a bounded blocking pool, token helpers andkey:generate.navree-audit: an audit trail of data changes, sign-ins, permission changes and access denials, withaudit:prune.
Background work
navree-queue: database and memory job queues with workers, retries with backoff, unique and delayed jobs, failed-job storage and thequeue:work,queue:failed,queue:retryandqueue:flushcommands. Jobs dispatched during a request are queued only if its transaction commits.navree-events: a typed event bus with synchronous and queued listeners.navree-schedule: cron-style schedules in UTC, overlap prevention, single-node runs across servers sharing a database, andschedule:run,schedule:workandschedule:list.
Communication
navree-mail: mailables rendered from templates, with SMTP, log, array and failover transports, and queued sending.navree-notify: notifications over mail, the database and broadcasts, with read state.navree-realtime: an in-process WebSocket server speaking the Pusher protocol, so Laravel Echo and pusher-js work unchanged, with public, private and presence channels and a signed relay that lets workers broadcast through the serving process.navree-view: MiniJinja templates for mail and other text.
Integrations and operations
navree-storage: named disks on object_store (local filesystem and memory), streaming, signed temporary URLs and upload checks.navree-http-client: outgoing HTTP with retries, timeouts, an SSRF policy and fakes for tests.navree-observe:/health/live,/health/readywith per-module checks, and Prometheus metrics at/metrics.
Testing
navree-testing:TestAppto boot an app or a few modules on a temporary database, an in-processTestClientwith cookies,acting_as, JSON assertions and validation-error assertions, and fakes.
The CLI
The navree binary (crate navree-cli) creates apps, generates code and runs the dev loop:
navree new <name>, with--ui nextfor a Next.js front end that keeps tokens in httpOnly cookies, and--navree-pathto choose the Navree checkout.navree make:module <name> [--crud]and twelvemake:<kind>generators: controller, service, entity, migration, job, event, listener, mail, notification, policy, command and test. Generators never overwrite files; they register what they create at marker comments.navree dev, which rebuilds and restarts the app when its code changes, and keeps the last good build serving when a build fails.- Every other command is forwarded to the app's binary.
The reference CRM
apps/crm-api is a CRM API built on Navree: companies, contacts, a deals pipeline, activities, a dashboard, users and roles, with live updates over WebSockets, queued notifications, scheduled reminders and an audit log. apps/crm-web is its Next.js front end, whose server holds the tokens for the browser. Unit, feature and Playwright end-to-end tests cover both. The CRM tour walks through it.
The benchmark
bench/ compares Navree with Loco, Axum, Actix Web, Gin, ASP.NET Core, Spring Boot, NestJS (Express and Fastify), Express, FastAPI, Django, Laravel (Octane and PHP-FPM) and Rails, each implementing the same API and passing the same conformance checks. Every implementation runs against PostgreSQL, Navree's included: its benchmark app uses navree-db's pool, the unit of work, pagination, Repo::insert and navree-auth's user lookup on a real PostgreSQL server, with no changes to the framework. The benchmarks page has the results.
Design decisions
A few things work differently from what the original plan described:
- Authentication and errors follow NestJS, not Laravel Sanctum. Navree issues stateless JWT access tokens and rotating refresh tokens; navree-auth has no SPA cookie authentication, no personal access tokens and no session login. Errors use NestJS's
{statusCode, message, error}format; there are noapplication/problem+jsonresponses and no 422 or 419 statuses. - Real time is built in. Instead of relying on an external WebSocket server, Navree ships an in-process Pusher-protocol server. Processes that don't serve the sockets send their broadcasts to the one that does over a signed HTTP relay.
- The framework's own crates don't use the macros. They implement
Module,InjectableandControllerby hand, the escape hatch every app can use too. Apps use the macros.
Known limitations
These are the gaps in 0.1.0 you may run into. Most are listed again, as future work, on the roadmap.
Installation and tooling
- The crates aren't on crates.io. Without a local checkout,
navree newwritesnavree = "0.1.0", which doesn't resolve yet. navree helpprints the CLI's own help, not your app's commands, although the generated README says otherwise. Usenavree list.navree devdoesn't keep the listening socket open across restarts, so requests fail while the server restarts. Ifnavree devis killed forcibly, the server it started keeps running.
Configuration
- In
ConfigSources::defaults(),config/app.tomloverrides.env, not the other way round. A key set in both keeps the TOML value, so editingAPP_HTTP__ADDRorAPP_DATABASE__URLin a new app's.envhas no effect. Real environment variables do override the file. The comments in the generated.env.exampleandconfig/app.tomldescribe this the wrong way round. See Configuration. ConfigSources::defaults()reads the realAPP_*environment variables, so tests that use it can be affected by the machine they run on. Build test configuration withConfigSources::new().
Database
- PostgreSQL support compiles and runs in the benchmark, but the test suite runs on SQLite only. Some PostgreSQL paths haven't been run against a real server yet, among them migrations, the
FOR UPDATErow locks inRepo::update,Repo::find_for_updateand record checks, and the queue'sFOR UPDATE SKIP LOCKEDjob reservation; the database page has the full list. - navree-db leaves sqlx's
test_before_acquireon, so each connection checkout costs an extra round trip, and there is no setting to turn it off.
Authentication and security
- A request with a present but invalid JWT gets a 401 on every route, public ones included. Clients must not send stale access tokens to
/api/auth/login,/api/auth/refreshor the health probes. - Access tokens are stateless: they stay valid until they expire (15 minutes by default), even after logout or a password change.
- The
refresh_tokenstable grows with every refresh and there is no command to prune it yet. A refresh token's lifetime slides: each rotation gets a fresh 30 days. - Registration, forgot-password and reset-password have no route-specific rate limits: only the global per-IP limit and the per-address mail throttle apply.
POST /api/auth/2fa/enableandPOST /api/auth/2fa/recovery-codesneed only a valid access token, not the password.- A bad or expired signed URL answers 401, where Laravel answers 403.
Validation and access
- serde errors (a wrong type, a missing field, an unknown enum value) are reported one at a time, before and instead of the garde rules. A body with an empty
nameand an invalidsizereports onlysize. - The record loader behind
#[can(.., from = "id")]has no soft-delete scope, so a user whose rules deny the action gets 403 rather than 404 on a soft-deleted record. Asyncexistsrules can't adddeleted_at IS NULLeither; check deleted records in your service. - A record check that fails answers 403 even when the user may not read the record, which tells the caller the id exists.
- There is no command to assign a role to a user; use the access management routes or a seeder.
OpenAPI
- The document can't describe query parameters or non-JSON bodies, such as a CSV export.
- navree-db's
Page<T>has no OpenAPI schema, so a paginated route documents its response with a page struct of its own, as the CRM'sDealPagedoes (#[api(response = DealPage)]). - The
userin login responses andGET /api/auth/meis documented without the fields an app adds to it. - Framework routes without schemas: the abilities and access management routes, broadcasting auth, the WebSocket endpoint, the health probes and
/metrics. - Every operation lists a
cookiesecurity scheme, even in apps that use bearer tokens only. - The docs UI loads its script from jsDelivr without a subresource integrity hash.
HTTP and other modules
- navree-http doesn't map multipart errors itself: only apps with
StorageModuleanswer malformed uploads with a 4xx instead of a 500. - navree-http-client can't pick up the current request's id on its own; pass it with
.with_request_id(&id). - The memory cache store has no size limit, and there are no Redis drivers for the cache, the queue, sessions, locks or real-time scaling.
- Storage disks are the local filesystem and memory only.
- navree-session still serves
GET /sanctum/csrf-cookie, a leftover from the original Sanctum plan. The module is optional.
Kernel and testing
- A singleton that stores the
AppContextcreates a reference cycle, so that app's memory is never freed. It doesn't matter for a long-running process, but leaks in tests that boot many apps; resolve lazily withr.lazy::<T>()instead. - A provider registered with
.lifecycle::<T>()must be a singleton. A request-scoped one fails at boot, andcheckdoesn't catch it. - On Windows, a
TestAppdropped withoutapp.shutdown().awaitmay leave its SQLite files in the temporary directory, because the pool is still open. TestAppBuilder::fake_authreplaces the app's authenticator completely, so one test app can't mixacting_aswith real bearer tokens.
Performance
Navree's own per-request cost is high for a Rust framework: on plain JSON it delivers 22% of a hand-written Axum service's throughput. The benchmark's findings trace this to specific parts of the pipeline, listed on the roadmap.
Deliberately deferred
Redis drivers, apalis as a queue backend, passkeys, social login, an OAuth2 server, billing, AI, gRPC, search and other modules were left out of 0.1 on purpose. The roadmap lists them with the reasons.