Rapina 0.5.0 shipped on February 18, 2026. This release focused on the database layer and developer tooling, adding migration support built on top of SeaORM and a scaffolding command that generates a full CRUD resource from a single command.
Database migrations
Migration support was added via sea-orm-migration. The CLI generated timestamped migration files, and the framework ran them at startup through the builder chain.
Generating a migration
rapina migrate new created a new migration file under src/migrations/:
rapina migrate new create_usersThis generated a timestamped file like src/migrations/m20260218_120000_create_users.rs with empty up and down methods to fill in, and updated src/migrations/mod.rs automatically.
Writing a migration
The generated file used sea-orm-migration conventions directly:
use rapina::sea_orm_migration;
use rapina::migration::prelude::*;
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table(
Table::create()
.table(Users::Table)
.col(
ColumnDef::new(Users::Id)
.integer()
.not_null()
.auto_increment()
.primary_key(),
)
.col(ColumnDef::new(Users::Name).string().not_null())
.to_owned(),
)
.await
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.drop_table(Table::drop().table(Users::Table).to_owned())
.await
}
}
#[derive(DeriveIden)]
enum Users {
Table,
Id,
Name,
}Wiring migrations at startup
The migrations! macro wired migration modules into the migrator, and .run_migrations() applied pending migrations before the server started accepting requests:
mod migrations;
use rapina::prelude::*;
use rapina::database::DatabaseConfig;
#[tokio::main]
async fn main() -> std::io::Result<()> {
let router = Router::new()
.get("/users", list_users);
Rapina::new()
.with_database(DatabaseConfig::new("sqlite://app.db?mode=rwc"))
.await?
.run_migrations::<migrations::Migrator>()
.await?
.router(router)
.listen("127.0.0.1:3000")
.await
}src/migrations/mod.rs declared the migration modules and registered them:
mod m20260218_120000_create_users;
rapina::migrations! {
m20260218_120000_create_users,
}.run_migrations() required .with_database() to have been called first. If the database was not configured, startup failed with a clear error.
rapina add resource
rapina add resource scaffolded a complete CRUD resource from the command line. It took a resource name and a list of typed fields:
rapina add resource user name:string email:string active:boolThis generated the following files:
src/users/mod.rs # Module declarations
src/users/handlers.rs # list, get, create, update, delete handlers
src/users/dto.rs # CreateUser, UpdateUser request types
src/users/error.rs # UserError with IntoApiError + DocumentedError
src/entity.rs # Appends a schema! {} block (or creates the file)
src/migrations/m{TS}_create_users.rs # Pre-filled migration
src/migrations/mod.rs # Updated with mod + migrations! macro entryThe generated handlers were ready to compile and followed the same patterns as handwritten Rapina code. After running the command, it printed the exact wiring instructions for main.rs:
Next steps:
1. Add the module declaration to src/main.rs:
mod users;
mod entity;
mod migrations;
2. Register the routes in your Router:
use users::handlers::{list_users, get_user, create_user, update_user, delete_user};
let router = Router::new()
.get("/users", list_users)
.get("/users/:id", get_user)
.post("/users", create_user)
.put("/users/:id", update_user)
.delete("/users/:id", delete_user);
3. Pass the router to Rapina:
Rapina::new()
.with_database(DatabaseConfig::new("sqlite://app.db?mode=rwc"))
.await?
.run_migrations::<migrations::Migrator>()
.await?
.router(router)
.listen("127.0.0.1:3000")
.awaitSupported field types
Fields used a name:type format. Twelve types were supported:
| Type | Aliases | Rust type |
|---|---|---|
string | String | |
text | String | |
i32 | integer | i32 |
i64 | bigint | i64 |
f32 | float | f32 |
f64 | double | f64 |
bool | boolean | bool |
uuid | Uuid | |
datetime | DateTime | |
date | Date | |
decimal | Decimal | |
json | Json |
The command failed fast if the resource directory already existed, to avoid overwriting existing code.
Documentation site UX
The docs site received several UX improvements:
- Search — Ctrl+K opened a search dialog powered by elasticlunr. Previously search was broken.
- Dark mode — the site followed the system color preference automatically.
- Mobile nav — the navigation no longer disappeared on small screens.
- Prev/next links — each page had navigation links at the bottom to move through the docs without scrolling back to the top.
- Restructured navigation — content was reorganized into Introduction > Getting Started > Core Concepts > CLI, making the flow clearer for newcomers.
- Landing page — the landing page was updated with a demo GIF showing the CLI in action and an FAQ section.
- Installation guide — the guide now covered installing Rust before installing Rapina.
Upgrade by bumping the version in your Cargo.toml:
rapina = "0.5.0"