Skip to main content

Basic storage migration

A simple migration guide using the Nicks pallet as a reference.


Write a storage migration for a pallet that adds an additional Vec<u8> storage item to runtime storage.

Use cases#

A pallet that adds a single storage item and needs to be included in a runtime upgrade.


This guide will step through a storage migration on FRAME's Nick's pallet. It shows how to modify a storage map to provide an optional field that includes a last name, and how to write the migration function ready to be triggered upon a runtime upgrade. This guide can equally be used in other contexts which require a simple storage migration that modifies a storage map in a runtime.


1. Create a storage struct and utility type#

Write a struct to manage the previous and new storage items, first and last:

pub struct Nickname {
first: Vec<u8>,
last: Option<Vec<u8>>, // handles empty storage

Write a utility type enum to keep track of the storage versions:

#[derive(codec::Encode, codec::Decode, Clone, frame_support::RuntimeDebug, PartialEq)]
pub enum StorageVersion {

2. Update your storage items#

The Nicks pallet only keeps track of a lookup table in storage, but we also need to add PalletVersion to declare the current version in storage. To update these items, use the Nickname struct in the NameOf item and add the new storage item PalletVersion:

decl_storage! {
trait Store for Module<T: Trait> as MyNicks {
/// The lookup table for names.
NameOf: map hasher(twox_64_concat) T::AccountId => Option<(Nickname, BalanceOf<T>)>;
/// The current version of the pallet.
PalletVersion: StorageVersion = StorageVersion::V1Bytes;

3. Update all functions#

All of the Nicks pallet functions need to account for the new last: Option<Vec<u8>> storage item. Update each function by adding it as a parameter, for example:

fn force_name(origin,
target: <T::Lookup as StaticLookup>::Source,
first: Vec<u8>,
last: Option<Vec<u8>>) {

In addition, update all storage writes with the Nickname struct:

<NameOf<T>>::insert(&sender, (Nickname { first, last }, deposit));

4. Declare a migration module#

The migration module should contain two parts:

  1. A module indicating the deprecated storage to migrate from.
  2. The migration function which returns a weight.

The scaffolding of this module looks like this:

pub mod migration {
use super::*;
pub mod v1 {...} // only contains V1 storage format
pub fn migrate_to_v2<T: Config>() -> frame_support::weights::Weight {...} // contains checks and transforms storage to V2 format

5. Write migrate_to_v2#

Here's an overview of what this function needs to do:

  • Check the storage version to make sure a migration is needed (good practice)
  • Transform the storage values into the new storage format
  • Update the storage version
  • Return the weight consumed by the migration

Check the storage version#

Construct the migrate_to_v2 logic around the check. If the storage migration doesn't need to happen, return 0:

if PalletVersion::get() == StorageVersion::V1Bytes {
// migrate to v2
} else {
frame_support::debug::info!(" >>> Unused migration!");

Transform storage values#

Using the translate storage method, transform the storage values to the new format. Since the existing nick value in storage can be made of a string separated by a space, split it at the ' ' and place anything after that into the new last storage item. If it isn't, last takes the None value:

NameOf::<T>::translate::<(Vec<u8>, BalanceOf<T>), _>(
|k: T::AccountId, (nick, deposit): (Vec<u8>, BalanceOf<T>)| {
// We split the nick at ' ' (<space>).
match nick.iter().rposition(|&x| x == b" "[0]) {
Some(ndx) => Some((Nickname {
first: nick[0..ndx].to_vec(),
last: Some(nick[ndx + 1..].to_vec())
}, deposit)),
None => Some((Nickname { first: nick, last: None }, deposit))

remove Option wrapping to make sure decoding works properly.

Return the consumed weight#

To do this, count the number of storage reads and writes and return the corresponding weight:

let count = NameOf::<T>::iter().count();
T::DbWeight::get().reads_writes(count as Weight + 1, count as Weight + 1)

Use migrate_to_v2 in on_runtime_upgrade#

Go back to the pallet's functions and specify the migrate_to_v2 function in on_runtime_upgrade:

fn on_runtime_upgrade() -> frame_support::weights::Weight {

6. Create a types.json file#

Put the new storage types in a types.json which you will need to trigger the migration using a UI. Our new types in JSON are:

"Nickname": {
"first": "Vec<u8>",
"last": "Option<Vec<u8>>"
"StorageVersion": {
"_enum": [



How-to guides#

Rust docs#

Was this guide useful?