Add a model
Goal: add a new database-backed model to a Loco app — a migration, a Sea-ORM entity, and your own model file to extend it — using the model generator.
This assumes a working Loco app with the with-db feature enabled (the default). For the full field-type mini-language and every generator kind, see Generators & field types. For the migration DSL used under the hood, see Schema & ColType DSL.
1. Generate the model
Section titled “1. Generate the model”Run the model generator with a name and a list of field:type pairs:
$ cargo loco generate model posts title:string! content:text user:referencesThis does three things in one step:
- Writes a migration under
migration/src/that creates apoststable. - Applies the migration against your development database.
- Regenerates Sea-ORM entities into
src/models/_entities/, and scaffoldssrc/models/posts.rsfor your own model code.
You end up with:
src/ models/ _entities/ posts.rs <-- generated entity (Entity, Model, ActiveModel, Column, Relation) posts.rs <-- your extension pointmigration/ src/ m20240101_000002_posts.rsSet the SKIP_MIGRATION environment variable if you want the generator to only write the migration file, without applying it or regenerating entities — useful when scripting several generate model calls back to back before running db migrate once at the end.
2. Read the field syntax
Section titled “2. Read the field syntax”Each field:type pair follows a small suffix convention:
- no suffix → nullable column (
Option<T>) !→ required column (NOT NULL)^→ unique column (impliesNOT NULL)
So title:string! is a required String, and content:text is a nullable Option<String>.
user:references is special: it doesn’t name a column type, it declares a belongs-to foreign key. It adds a required user_id column referencing the users table (user:references? makes it nullable; user:references:author_id picks a custom column name). See Generators & field types § References for the full syntax.
int/int!/int^ field type now maps to i64 / BIGINT (big_integer), not i32 as in earlier Loco versions — matching the framework's i64 auto-increment primary keys. Use small_int if you specifically need a 16-bit column.
3. Add more fields to an existing model
Section titled “3. Add more fields to an existing model”To add columns to a table you already created, generate a plain migration instead of a new model — name it Add<Columns>To<Table> so Loco infers an “add columns” migration:
$ cargo loco generate migration AddViewsToPosts views:intApply it and regenerate entities:
$ cargo loco db migrate$ cargo loco db entitiesRemoving columns follows the mirror-image naming convention, Remove<Columns>From<Table>:
$ cargo loco generate migration RemoveViewsFromPosts views:intExpect a few test failures right after db entities: a generated app’s tests snapshot whole models (assert_debug_snapshot!(user)), so an added column changes their output. Re-accept the snapshots in the same commit as the migration — see Fixtures & snapshots.
4. Generate without timestamps (optional)
Section titled “4. Generate without timestamps (optional)”By default every table generated through the DSL gets created_at/updated_at columns. To opt out, pass --without-tz to model, migration, or scaffold:
$ cargo loco generate model posts title:string! content:text --without-tz--without-tz, not --without-timestamps — an older spelling that no longer works.
5. Verify
Section titled “5. Verify”Confirm the migration applied and entities exist:
$ cargo loco db status$ ls src/models/_entities/Then write against the model directly — e.g. in a cargo playground script or a test:
use loco_rs::testing::prelude::*;use myapp::app::App;use myapp::models::_entities::posts;
let boot = boot_test::<App>().await?;let post = posts::ActiveModel { title: sea_orm::ActiveValue::set("hello".to_string()), user_id: sea_orm::ActiveValue::set(1), ..Default::default()}.insert(&boot.app_context.db).await?;
assert_eq!(post.title, "hello");Result: a posts table exists in your database, posts::Entity/Model/ActiveModel compile, and src/models/posts.rs is where you add custom methods (e.g. Model::find_by_title) the same way examples/demo/src/models/users.rs extends the generated users entity.
- Query data with the
ConditionBuilderDSL. - Foreign-key relationships and request/model validation beyond a single table.