12 stable releases
| 1.9.0 | Oct 26, 2025 |
|---|---|
| 1.8.0 | Oct 20, 2025 |
| 1.5.0 | Sep 27, 2025 |
| 0.1.2 | Aug 17, 2025 |
#355 in HTTP server
35KB
471 lines
🚀 Velto
A minimal async web framework for Rust, built for clarity, speed, and joy.
✨ Features
- 🧭 Intuitive routing with
route!(...)androute_any!(...)macros - 🧵 Templating with
render!,{% include %}, and{% extends %}support - ⚡ Fully async, powered by
async_tiny - 🔄 LiveReload support in development mode
- 📁 Static file serving with zero config
- 🔌 Global middleware support via
App::use_middleware() - 🧠 Minimal boilerplate via
velto::prelude - 🧪 Built-in testing with
TestRequest - 🛠 First-class CLI support via
velto-cli
📦 Installation
Add Velto to your Cargo.toml:
[dependencies]
velto = "1.9.0"
Or use velto-cli to scaffold a new project instantly:
cargo install velto-cli
velto new my-app
cd my-app
velto run
🚀 Quick Start
use velto::prelude::*;
use velto::middleware::logger; // Built-in middleware
fn homepage(_req: &Request) -> Response {
render!("index.html", {
"title" => "Welcome to Velto",
"message" => "Fast. Clean. Rusty."
})
}
#[tokio::main]
async fn main() -> std::io::Result<()> {
let mut app = App::new();
app.use_middleware(logger); // Add middleware
app.enable_dev_mode(); // Enables LiveReload
route!(app, "/" => homepage);
app.serve_static("static");
app.run("127.0.0.1:8080").await
}
🔌 Middleware
Velto supports global middleware functions that run before and/or after route handlers.
Use App::use_middleware() to register middleware like logging, authentication, or header injection.
Example: Logger Middleware
pub fn logger(req: &Request, next: &dyn Fn(&Request) -> Response) -> Response {
println!("📥 {} {}", req.method(), req.url());
let res = next(req);
println!("📤 Responded with {}", res.status_code());
res
}
- Middleware is synchronous and composable
- Multiple middleware are executed in registration order
- Built-in
loggermiddleware is available invelto::middleware
🔄 LiveReload
Velto automatically watches your static/ and templates/ directories in dev mode.
When a file changes, connected browsers reload instantly via WebSocket.
No setup required. Just call:
app.enable_dev_mode();
🧪 Testing
Velto includes a built-in TestRequest type for simulating requests in unit tests:
#[test]
fn test_homepage() {
let mut app = App::new();
route!(app, "/" => |_req| {
Response::from_string("Hello, test!")
});
let res = velto::test::TestRequest::new("GET", "/").send(&app);
assert_eq!(res.status_code(), 200);
assert!(res.body().contains("Hello"));
}
No external test harness required — just write Rust tests and run cargo test.
🧰 Project Structure
Velto is organized into modular components for clarity and maintainability:
velto/
├── src/
│ ├── app.rs # Core application logic
│ ├── dev.rs # Dev mode toggles and helpers
│ ├── form.rs # Form data parsing
│ ├── http_method.rs # HTTP method utilities
│ ├── macros.rs # Macros for render! and route!
│ ├── middleware.rs # Middleware system and built-in examples
│ ├── prelude.rs # Public API surface
│ ├── reload.rs # LiveReload WebSocket + file watcher
│ ├── response.rs # HTTP response utilities including redirect helpers
│ ├── router.rs # Routing and handler dispatch
│ ├── template.rs # Templating engine with include/inheritance
│ ├── test.rs # TestRequest and internal test harness
│ ├── util.rs # Utility functions (e.g., MIME types)
│ └── lib.rs # Entry point
❓ Why Velto
Velto is for developers who want:
- A fast, async-native web framework without the complexity of full-stack giants
- Clean routing and templating without ceremony
- Instant LiveReload for a smooth development loop
- A modular codebase that grows with your project
- A framework that feels like Rust — not like a port of something else
Whether you're building a personal site, a microservice, or a dev tool, Velto gives you just enough structure to stay productive — and just enough freedom to stay creative.
🔁 Migration from 0.x
Velto 1.0.0 introduced async support and LiveReload, but kept the public API familiar. Here's what changed:
| Old (0.x) | New (1.0.0) |
|---|---|
fn main() |
#[tokio::main] async fn main() |
Response<Cursor<Vec<u8>>> |
Response (no generics) |
app.run(...) |
app.run(...).await |
| No LiveReload | app.enable_dev_mode() |
Most route handlers and macros (route!, render!) remain unchanged.
Just update your main() function and remove Cursor<Vec<u8>> from response types.
📄 License
MIT — free to use, modify, and distribute.
💬 Contributing
Velto is evolving rapidly. If you have ideas, feedback, or want to help shape its future, open an issue or submit a PR.
We welcome clean code, thoughtful design, and good vibes.
Dependencies
~8–21MB
~227K SLoC