# How to migrate running canisters from `std` collections to `ic-stable-memory` > Warning! > > It is strongly suggested to NOT migrate canisters, which already have at least 1GB memory occupied by > their state. Migration happens in the `#[post_upgrade]` canister method, so any bad thing that may happen will **BREAK** > your canister permanently. > > Let them work as they work now. Spin up fresh canisters, that were written with `ic-stable-memory` from scratch and > find a way to include them into the rest of your app. > > **But do not migrate old heavy canisters**. First of all, `ic-stable-memory` collections have a very similar API to `std` collections. So, you should be able to migrate with as few changes as possible. Let's imagine we have a canister like this ```rust thread_local! { static STATE: RefCell>> = RefCell::default(); } #[init] fn init() { STATE.with(|state| { *state.borrow_mut() = Some(Vec::new()); }); } #[post_upgrade] fn post_upgrade() { STATE.with(|state| { *state.borrow_mut() = Some(retrieve_state_from_stable_memory()); }) } #[pre_upgrade] fn pre_upgrade() { STATE.with(|state| { let state = state.borrow_mut().take().unwrap(); store_state_to_stable_memory(state); }) } ``` Migration to `ic-stable-memory` takes **two** canister upgrades. During the first one you transfer all your data from `std` collections into stable ones. During the second upgrade you clean up the migration code. ### First upgrade ```rust thread_local! { static STATE: RefCell>> = RefCell::default(); // <- notice Vec changed to SVec } // <- notice there is no #[init], you can keep it, but there is no point in that in production #[post_upgrade] fn post_upgrade() { stable_memory_init(); // <- init stable memory allocator as the FIRST line // get the old state from stable memory as usual let old_state: Vec = retrieve_state_from_stable_memory(); // create a stable collection to move the state there let new_state = SVec::::new_with_capacity(old_state.len()) .expect("Out of memory"); // <- this is very dangerous, since it can break your canister // move the state to stable collection for entry in old_state { new_state.push(entry).unwrap(); } // use stable collection instead of the old one STATE.with(|state| { *state.borrow_mut() = Some(new_state); }); } #[pre_upgrade] fn pre_upgrade() { // take the collection from static as usual let state = STATE.with(|state| { state.borrow_mut().take().unwrap() }); // put it in a SBox let boxed_state = SBox::new(state).expect("Out of memory"); // persist the pointer to that SBox between upgrades store_custom_data(1, boxed_state); // persist the memory allocator between upgrades stable_memory_pre_upgrade().expect("Out of memory"); } ``` ### Second upgrade For the next canister upgrade you have to only update the `#[post_upgrade]` hook - everything else stays the same: ```rust #[post_upgrade] fn post_upgrade() { stable_memory_post_upgrade(); // <- instead of stable_memory_init() // retrieve the pointer to the SBox back let boxed_state = retrieve_custom_data::>(1).unwrap(); // transform that SBox back into the state let state = boxed_state.into_inner(); // put state into static variable STATE.with(|s| { *s.borrow_mut() = Some(state); }); } ``` This is a simple example, but essentially you will have to complete the same steps for any other situation: * Move data from `std` collections to `ic-stable-memory` collections, during first canister upgrade. * Replace the `#[post_upgrade]` method with the one that only works with stable structures, during the second canister upgrade. ### Rest of the code Everything else should work as usual. `ic-stable-memory` collections API is not as rich as `std`'s one, so sometimes you'll have to find a way of how to transform a high-level method into a set of lower-level ones, but there is no difference between them besides that.