Migrations and Schema
Relevant source files
The following files were used as context for generating this wiki page:
Migrations and schema management in Loco provide a structured way to evolve a database over time using Rust-based migration files. Leveraging SeaORM under the hood, Loco allows developers to define, execute, and rollback database changes through a unified Command Line Interface (CLI). This system ensures that the database state remains consistent with the application's data models while providing automated generation tools to reduce manual coding.
The workflow typically involves generating a migration, applying it to the database, and then generating or updating the corresponding Rust entities. This ensures that the application's compiled code is always in sync with the underlying database schema.
Sources: DEVELOPMENT.md:33-41, src/cli.rs:260-290
Migration Architecture and Logic
Loco's migration system is built on a "convention over configuration" approach. The framework uses specialized inference logic to determine the intent of a migration based on its name. For example, a migration named CreateUsers is automatically inferred as a table creation task, while AddEmailToUsers is inferred as a column addition task.
Migration Inference Logic
When a user requests a new migration via the CLI, the loco-gen module parses the name to select the appropriate template.
This diagram shows how Loco decides which internal template to use based on the string input provided by the user.
Sources: loco-gen/src/infer.rs:58-94, loco-gen/src/migration.rs:27-65
Core Components
The system relies on several key modules and traits to perform operations:
| Component | Responsibility |
|---|---|
MigrationTrait | The standard trait implemented by every migration file defining up and down methods. |
SchemaManager | A SeaORM utility used within migrations to execute SQL commands like create_table or drop_table. |
loco_gen::infer | Analyzes migration names and field strings to guess types and parameters. |
loco_rs::schema | Provides helper functions and types (e.g., ColType) for defining table structures. |
Sources: loco-new/base_template/migration/src/m20220101_000001_users.rs:7-10, loco-gen/src/infer.rs:6-15
Command Line Interface (CLI) Operations
Loco exposes migration and schema management through the db and generate (or g) subcommands. These commands allow for the full lifecycle management of the database schema.
Database Management Commands
The following table summarizes the primary database commands available through the CLI:
| Command | Action |
|---|---|
loco db create | Creates the database defined in the configuration. |
loco db migrate | Runs all pending migrations (up). |
loco db down [N] | Rolls back the last N migration(s). |
loco db reset | Drops all tables and reapplies all migrations from scratch. |
loco db status | Checks the status of migrations. |
loco db entities | Generates Rust entity files from the current DB schema. |
loco db schema | Dumps the current database schema to a JSON file. |
Sources: src/cli.rs:434-457, DEVELOPMENT.md:33-41
Generation Flow
The generation of migrations often happens in tandem with model scaffolding.
This sequence illustrates the interaction between the developer and the generator when creating a new schema change.
Sources: loco-gen/src/migration.rs:24-30, src/cli.rs:240-255
Defining Migration Files
Migrations are written in Rust and implement the MigrationTrait. They consist of two primary functions: up (to apply changes) and down (to revert them).
Schema Helpers
Loco provides a wrapper around SeaORM's migration logic to simplify column definitions using ColType.
// Example of a generated migration structure
async fn up(&self, m: &SchemaManager) -> Result<(), DbErr> {
create_table(
m,
"users",
&[
("id", ColType::PkAuto),
("email", ColType::StringUniq),
("name", ColType::String),
("reset_sent_at", ColType::TimestampWithTimeZoneNull),
],
&[],
).await?;
Ok(())
}
Sources: loco-new/base_template/migration/src/m20220101_000001_users.rs:10-30
Field Parsing
The generator supports various field types and constraints passed via the command line, such as references for foreign keys.
| Input Syntax | Inferred Field Type |
|---|---|
name:string | Standard String column |
user:references | Foreign key referencing the users table |
email:string! | Non-nullable String column |
bio:text? | Nullable Text column |
Sources: loco-gen/src/infer.rs:25-45, loco-gen/tests/db.rs:52-64
Schema Synchronization
A critical part of the Loco workflow is keeping Rust entities in sync with the database. After a migration is applied, the developer must run loco db entities. This command connects to the actual database, inspects the schema, and regenerates the Rust code in src/models/_entities.
Automatic Timestamps
By default, Loco's generators add created_at and updated_at timestamps to migrations unless the --without-tz flag is used. The generator logic specifically ignores these fields during certain manual generation tasks because they are considered "blessed" fields managed by the framework.
Sources: loco-gen/src/migration.rs:13-15, src/cli.rs:228-235
Schema Dumps
Loco can generate a schema_dump.json. This is used for snapshot testing and provides a portable representation of the database structure at a specific point in time.
Sources: loco-gen/tests/db.rs:104-108, src/cli.rs:458
Summary
The Migrations and Schema system in Loco provides a robust, developer-friendly interface for database evolution. By combining powerful CLI generators with the type safety of Rust and the flexibility of SeaORM, Loco automates the boilerplate associated with database management. Developers can move from a simple CLI command to a fully migrated database and updated application entities in seconds, maintaining a strong link between the database schema and the application's code.