Manage world migrations, handle breaking changes, and upgrade Dojo versions. Use when updating deployed worlds, migrating to new versions, or handling schema changes.
Handle world migrations, upgrades, and breaking changes when updating deployed Dojo worlds.
Manages migration workflows:
Update existing world:
"Migrate my changes to the deployed world"
Version upgrade:
"Upgrade my project to Dojo v1.8.0"
sozo inspect
Shows:
sozo build
sozo test
# Deploy with default dev profile
sozo migrate
# Deploy with specific profile
sozo migrate --profile sepolia
Adding new model:
// New model - safe to add
#[derive(Copy, Drop, Serde)]
#[dojo::model]
pub struct NewFeature {
#[key]
pub player: ContractAddress,
pub data: u32,
}
Adding new system:
// New system - safe to add
#[dojo::contract]
pub mod new_system {
// Implementation
}
Adding model field:
// Adding field - existing data will have default (zero) value
struct Position {
#[key] player: ContractAddress,
x: u32,
y: u32,
z: u32, // New field
}
Changing key fields:
// Old
struct Position {
#[key] player: ContractAddress,
x: u32, y: u32,
}
// New - BREAKING! Different key structure
struct Position {
#[key] entity_id: u32, // Changed key
x: u32, y: u32,
}
Removing fields:
// Old
struct Stats {
#[key] player: ContractAddress,
health: u8,
mana: u8,
}
// New - BREAKING! Data loss
struct Stats {
#[key] player: ContractAddress,
health: u8,
// mana removed
}
Changing field types:
// Old
struct Position {
#[key] player: ContractAddress,
x: u32,
y: u32,
}
// New - BREAKING! Type incompatible
struct Position {
#[key] player: ContractAddress,
x: u128, // Changed type
y: u128,
}
Deploy fresh world with different seed:
# dojo_dev.toml
[world]
seed = "my_game_v2" # Different seed = new world address
sozo build && sozo migrate
Keep both old and new versions:
// Keep old model
#[derive(Copy, Drop, Serde)]
#[dojo::model]
pub struct PositionV1 {
#[key] player: ContractAddress,
x: u32, y: u32,
}
// Add new model
#[derive(Copy, Drop, Serde)]
#[dojo::model]
pub struct PositionV2 {
#[key] entity_id: u32,
x: u32, y: u32, z: u32,
}
Create a migration system to transform data:
#[dojo::contract]
pub mod migrator {
fn migrate_positions(ref self: ContractState, players: Array<ContractAddress>) {
let mut world = self.world_default();
for player in players {
// Read old format
let old_pos: PositionV1 = world.read_model(player);
// Transform to new format
let new_pos = PositionV2 {
entity_id: world.uuid(),
x: old_pos.x,
y: old_pos.y,
z: 0,
};
// Write new format
world.write_model(@new_pos);
}
}
}
Scarb.toml:[dependencies]
dojo = "1.8.0"
[dev-dependencies]
dojo_cairo_test = "1.8.0"
Review changelog for breaking changes
Build and test:
sozo build
sozo test
sozo migrate
sozo inspectsozo build)sozo test)sozo migrate)# 1. Add model to code
# 2. Build
sozo build
# 3. Migrate
sozo migrate
# 4. Verify
sozo inspect
# 1. Update system code
# 2. Build and test
sozo build
sozo test
# 3. Migrate (redeploys system)
sozo migrate
# 4. Test updated system
sozo execute my_game-actions spawn
sozo build firsttarget/ directory and rebuildsozo inspect outputAfter migration:
sozo build --typescript)dojo-indexer skill)