Velto - Rust async web framework (releases)

Velto is a minimal async web framework for Rust, built on async_tiny

Links
Crates.io
Github

Velto 1.3.0 has been released.

New in 1.3.0

  • method aware routing (GET, POST, etc)
  • enhanced route macro (route!(app, GET "/signup" => show_signup))

Example

use velto::prelude::*;

/// GET handler for the signup page.
/// Renders the `signup.html` template from the `templates/` directory.
fn show_signup(_req: &Request) -> Response {
    render!("signup.html", {
        "title" => "Sign Up"
    })
}

/// POST handler for form submission.
/// Parses the form body and responds with a confirmation message.
fn handle_signup(req: &Request) -> Response {
    let form = parse_form(std::str::from_utf8(req.body()).unwrap_or(""));

    let username = form.get("username").map(|s| s.as_str()).unwrap_or("");
    let password = form.get("password").map(|s| s.as_str()).unwrap_or("");

    let reply = format!("Signed up as: {}\nPassword: {}", username, password);
    Response::from_string(reply).with_content_type("text/plain")
}

#[tokio::main]
async fn main() -> std::io::Result<()> {
    let mut app = App::new();

    // Register GET and POST routes for "/signup"
    // GET shows the form, POST handles submission
    route!(app, GET "/signup" => show_signup);
    route!(app, POST "/signup" => handle_signup);

    // Serve static files from the "static/" directory
    app.serve_static("static");

    // Start the server on localhost:8080
    app.run("127.0.0.1:8080").await
}

Velto 1.4.0 released (Sep 20, 2025)

Velto now supports multi-method routing with a single handler:

  • route!(app, [GET, POST] "/signup" => signup)
  • New route_any! macro for registering a handler across all standard methods

Example

use velto::prelude::*;

fn signup(req: &Request) -> Response {
    match req.method().as_str() {
        "POST" => {
            let form = parse_form(std::str::from_utf8(req.body()).unwrap_or(""));
            let username = form.get("username").map(|s| s.as_str()).unwrap_or("");
            let password = form.get("password").map(|s| s.as_str()).unwrap_or("");
            let reply = format!("Signed up as: {}\nPassword: {}", username, password);
            Response::from_string(reply).with_content_type("text/plain")
        }
        _ => {
            render!("signup.html", {
                "title" => "Sign Up"
            })
        }
    }
}

#[tokio::main]
async fn main() -> std::io::Result<()> {
    let mut app = App::new();

    // Register both GET and POST methods with one handler
    route!(app, [GET, POST] "/signup" => signup);

    app.serve_static("static");
    app.run("127.0.0.1:8080").await
}

Velto 1.5.0 released (Sep 27, 2025)

New redirect helpers:

  • redirect("/dashboard") for redirecting to the specified location
  • redirect_with_status for redirecting with a custom status code, e.g. redirect_with_status("/new-url", 301);

Example

use velto::prelude::*;

fn signup(req: &Request) -> Response {
    match req.method().as_str() {
        "POST" => {
            let form = parse_form(std::str::from_utf8(req.body()).unwrap_or(""));
            let username = form.get("username").map(|s| s.as_str()).unwrap_or("");
            let password = form.get("password").map(|s| s.as_str()).unwrap_or("");
            let reply = format!("Signed up as: {}\nPassword: {}", username, password);
            Response::from_string(reply).with_content_type("text/plain")
        }
        _ => {
            render!("signup.html", {
                "title" => "Sign Up"
            })
        }
    }
}

#[tokio::main]
async fn main() -> std::io::Result<()> {
    let mut app = App::new();

    // Register both GET and POST methods with one handler
    route!(app, [GET, POST] "/signup" => signup);

    app.serve_static("static");
    app.run("127.0.0.1:8080").await
}

Velto 1.6.0 released (Oct 9, 2025)

Velto now automatically maps MIME types for all served files. For example, .html files are served with:

Content-Type: text/html; charset=utf-8

This ensures proper rendering across browsers and prevents issues like stylesheets being blocked due to missing MIME types.

Note: This release does not include any user-facing changes.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.