Batteries-Included Features

Floz provides a massive ecosystem for building production backends, eliminating the need to wire up dozens of unmaintained third-party dependencies.

🛡️

Input Validation

Automatic declarative payload and query string validation based on safe Rust type definitions.

🔒

Auth Guards

Macro-driven route protection supporting multiple guards natively in the router with O(1) checking.

🍪

Session Management

Built-in Redis-backed stateful sessions with cryptographically secure cookie handling.

🔑

JWT & API Keys

Native utility libraries for generating, hashing, and enforcing short-lived and permanent credentials.

Rate Limiting

Declarative, Redis-backed sliding window rate limits wired directly into the #[route] macros.

🔄

WebSockets & Channels

Zero-dependency, in-memory WebSocket multiplexing with declarative channel-gated authentication.

🚀

Background Workers

Celery-inspired Redis task queue with scheduling, retries, and failure back-offs.

⏱️

Scheduled Cron Tasks

App-level repeating tasks that run alongside the HTTP server for continuous polling jobs.

🗂️

File Uploads

Extremely ergonomic native handling of multipart form-data for robust local and object storage.

🧪

Testing Utilities

A fluent testing abstraction for integration-level endpoint assertions without needing network ports.

🩺

Health & Readiness

Auto-mounted standard endpoints that recursively verify DB and Redis dependencies are alive.

📊

Database Observability

Native exposure of SQLx connection pool lifecycle metrics (idle vs active vs max).

🔐

Auto HTTPS / TLS

Effortlessly wire certificate paths to enable HTTPS on the dev server without an Nginx proxy.

⚙️

Config Profiles

Smart environment cascading that merges .env, .env.development, and .env.production.

🛑

Graceful Shutdown

Drain Ntex in-flight HTTP requests and worker processes securely upon receiving a SIGTERM.

🧱

Security Tuned

Immediate protection via strict body size limits, CSRF mitigations, and HTTP security headers.

📻

PG LISTEN/NOTIFY

Bridge database channel events natively directly to active users without an intermediary service.

📖

Auto-OpenAPI Docs

Fully compliant Swagger JSON synthesised dynamically from your route handlers at bootup.

Background Task Queue

A Celery-inspired Redis-backed asynchronous queue system with zero-config discovery.

Defining Tasks

#[floz::task(queue = "default", max_retries = 3)]
async fn send_email(to: String, subject: String) -> Result<(), floz::FlozError> {
    // Do background work...
    Ok(())
}

Dispatching Tasks

// Dispatch immediately
send_email::dispatch("user@example.com".into(), "Welcome".into())
    .enqueue()?;

// Schedule with delay
send_email::dispatch("admin@site.com".into(), "Daily Report".into())
    .delay(chrono::Duration::hours(24))
    .enqueue()?;

Worker Runtime

// Start 4 concurrent worker threads alongside the web server
floz::App::new()
    .with_worker(4)
    .run(|cfg| {
        app::configure(cfg);
    })
    .await

Note: Requires the worker feature flag and a valid REDIS_URL configured in your environment.

Auth & Sessions

Declarative, zero-overhead macro-driven security maps powered by Redis sessions and JWT token validation.

Declarative Route Protection

Protect a route using `auth` and `permissions` keys in your `#[route(...)]` macro. The global `AuthMiddleware` interprets these rules during request processing with O(1) matching.

#[route(
    get: "/admin/dashboard",
    auth: "jwt,session",
    permissions: ["admin"]
)]
async fn admin_panel(ctx: Context) -> HttpResponse {
    // Automatically protected! Only accessible to admins.
    let user_id = ctx.req.auth.unwrap().user_id;
    // ...
}

Session Injection

Add SessionMiddleware::new() to your App builder to attach Redis-backed user sessions seamlessly.

let session = ctx.session();
session.set("cart_data", "items_xyz").await?;
let items: String = session.get("cart_data").await?.unwrap();

JWT & API Keys

let (token, expiry) = jwt::create_token(
    "user-123", "admin", b"secret",
    "my-app", "floz", 24,  // hours
)?;

let key = api_key::generate_api_key("sk");
let hash = api_key::hash_api_key(&key)?;        // bcrypt

PG LISTEN/NOTIFY

Because Floz is strictly coupled with sqlx, you get native access to Postgres' powerful real-time pub/sub event system directly from your handlers.

Streaming DB Changes

Use PgListener to bind a websocket or an SSE (Server-Sent Events) stream natively from the database — no external Redis brokers needed!

use sqlx::postgres::PgListener;

#[route(get: "/live-updates", tag: "Streams")]
async fn live_updates(ctx: Context) -> HttpResponse {
    let mut listener = PgListener::connect_with(&ctx.app.db().pool).await.unwrap();
    listener.listen("table_updates").await.unwrap();

    // Bridge Postgres payloads directly to your active client via Ntex streams!
    while let Some(notification) = listener.recv().await.unwrap() {
        println!("Live db event: {}", notification.payload());
    }
    
    res!("Ok")
}

WebSocket Channels

Zero-dependency, in-memory WebSocket multiplexing. Easily stream events to authorized clients through a single unified connection.

Declarative Channel Security

Use #[channel_gate] to intercept channel subscription requests (e.g. org_123) and validate them inside a handler before they mount. Variables in the pattern are securely mapped to parameters.

#[channel_gate("org_{org_id}")]
async fn check_org_access(ctx: Context, org_id: String) -> bool {
    let user = ctx.req.auth.unwrap();
    // Only return true if authorized
    UserRole::has_role(&ctx.app.db(), user.user_id, &org_id).await
}

Server-Side Publishing

Because Floz manages the connection pool in memory, any route or background task can instantly push messages down the socket without Redis PubSub bottlenecks.

#[route(post: "/orgs/:id/ping")]
async fn send_ping(path: Path<String>, ctx: Context) -> HttpResponse {
    let channel = format!("org_{}", path.into_inner());
    // Pushes to all connected WebSockets subscribed to this channel
    ctx.app.broadcast(&channel, &json!({ "event": "ping" }));
    res!("Done")
}

Logging

Daily-rotating log files with stdout mirroring. Auto-initialized by App::run().

// Auto-initialized when logger feature is enabled
floz::logger::init_tracing();

// Output: logs/my-app.log.2026-04-03
// Daily rotation, non-blocking writes
// Override filter via RUST_LOG env var

Utility Macros

MacroDescriptionExample
res!(body)JSON response (200 or custom status)res!(body, 201)
pp!(&data)Pretty-print in DEV, compact in PRODpp!(&users).unwrap()
echo!(...)Debug log only when ECHO is setecho!("user {}", id)
xquery!(sql, ...)SQLx query with auto-bindxquery!("SELECT...", id)
to_json!(row)Convert sqlx::Row to JSON mapto_json!(row)

Controller Utilities

JsonResponse

JsonResponse::ok(&users)              // 200 (pretty in DEV)
JsonResponse::created(&user)          // 201
JsonResponse::no_content()            // 204
JsonResponse::bad_request("Invalid")  // 400
JsonResponse::not_found("Not found")  // 404

PaginationParams

// Auto-extracted from query string
// /users?limit=20&offset=0&order_by=name&search=alice

#[ntex::web::get("/users")]
async fn list(params: web::types::Query<PaginationParams>) -> HttpResponse {
    let p = params.into_inner();
    // p.limit, p.offset, p.order_by, p.filter, p.search
}

CLI Tool

The floz-cli scaffolds projects and generates domain modules.

$ floz new my-app --template api
$ floz generate model Post title:string body:text
$ floz generate scaffold Post title:string body:text

# Generates: src/app/post/{mod,model,route}.rs

Project Templates

TemplateFeaturesUse Case
minimalSingle-file server + healthMicroservices
apiModular src/app/ structureREST APIs
saasFull: auth + workers + RedisSaaS apps