# How Consensus Version Upgrades and Module Migrations Work in Akash

> Understand Akash's consensus version upgrades and module migrations. Learn how Tendermint parameters move to the x/consensus store and data transforms via handlers automatically.

- Repository: [Akash Network/node](https://github.com/akash-network/node)
- Tags: internals
- Published: 2026-02-24

---

**Consensus version upgrades migrate core Tendermint parameters from the legacy `x/params` module to the dedicated `x/consensus` store, while module migrations transform stored data between versions via registered handlers that execute automatically at the upgrade height.**

The `akash-network/node` repository implements a robust on-chain upgrade mechanism built on the Cosmos SDK **Upgrade module**. Understanding how consensus version upgrades and module migrations work is essential for validators and developers maintaining the Akash blockchain. These mechanisms ensure seamless transitions between protocol versions without requiring manual state exports or hard forks.

## Consensus Version Upgrades in Akash

Consensus version upgrades represent major structural changes to how the network stores and manages core Tendermint parameters. These upgrades modify the blockchain's underlying storage layout and module configuration.

### Migrating from x/params to x/consensus

Prior to **Akash v1.0.0**, Tendermint consensus parameters—such as `max_gas` and `block_time`—were stored in the generic `x/params` sub-store. The consensus version upgrade creates a dedicated **`x/consensus`** module and migrates these parameters into an isolated store. This aligns Akash with the upstream Cosmos SDK v0.53.x consensus model.

The migration is performed by `baseapp.MigrateParams`, which transfers values from the legacy subspace to the new consensus params store:

```go
// upgrades/software/v1.0.0/upgrade.go
baseAppLegacySS := up.Keepers.Cosmos.Params.Subspace(baseapp.Paramspace)
...
err := baseapp.MigrateParams(sctx, baseAppLegacySS,
        up.Keepers.Cosmos.ConsensusParams.ParamsStore)

```

### Store Upgrades and the v1.0.0 Implementation

Alongside parameter migration, the upgrade modifies the multistore layout through the `StoreUpgrades` struct. In [`upgrades/software/v1.0.0/upgrade.go`](https://github.com/akash-network/node/blob/main/upgrades/software/v1.0.0/upgrade.go), the `StoreLoader` adds the new `consensus` store while removing deprecated modules:

```go
// upgrades/software/v1.0.0/upgrade.go
return &storetypes.StoreUpgrades{
    Added: []string{consensustypes.ModuleName}, // "consensus"
    Deleted: []string{ "agov", "astaking", crisistypes.ModuleName },
}

```

The upgrade also integrates the new module into the application by adding it to the module manager in [`app/modules.go`](https://github.com/akash-network/node/blob/main/app/modules.go) and instantiating its keeper in [`app/types/app.go`](https://github.com/akash-network/node/blob/main/app/types/app.go). Once the block at the upgrade height is committed, the chain's consensus version reflects the new parameters, and the old sub-store is permanently removed.

## Module Migrations

While consensus upgrades handle global parameter storage, **module migrations** evolve individual Akash modules (such as `market` or `deployment`) from one storage version to another. Each migration is a handler that transforms stored data and updates the module's version in the module manager.

### Registration Flow and Migration Handlers

Module migrations follow a declarative registration pattern centered in [`upgrades/types/types.go`](https://github.com/akash-network/node/blob/main/upgrades/types/types.go). The process involves four distinct steps:

1. **Define the migration** – Implement the `Migration` interface, which exposes an `sdkmodule.MigrationHandler`.
2. **Register the migration** – Call `utypes.RegisterMigration` with the module name, target version, and constructor function.
3. **Register the upgrade** – Associate the migrations with a specific upgrade name using `utypes.RegisterUpgrade`.
4. **Wire into the app** – During `AkashApp.registerUpgradeHandlers()` in [`app/upgrades.go`](https://github.com/akash-network/node/blob/main/app/upgrades.go), iterate all registered migrations and register them with the SDK's configurator.

For example, the market module migration for v1.2.0 is registered in [`upgrades/software/v1.2.0/init.go`](https://github.com/akash-network/node/blob/main/upgrades/software/v1.2.0/init.go):

```go
// upgrades/software/v1.2.0/init.go
utypes.RegisterMigration(mv1.ModuleName, 7, newMarketMigration)
utypes.RegisterUpgrade(UpgradeName, initUpgrade)

```

The global `migrations` map in [`upgrades/types/types.go`](https://github.com/akash-network/node/blob/main/upgrades/types/types.go) stores these registrations, keyed by module name and version. During application initialization, [`app/upgrades.go`](https://github.com/akash-network/node/blob/main/app/upgrades.go) wires them into the module configurator:

```go
// app/upgrades.go
utypes.IterateMigrations(func(module string, version uint64, initfn utypes.NewMigrationFn) {
    migrator := initfn(utypes.NewMigrator(app.cdc, app.GetKey(module)))
    app.Configurator.RegisterMigration(module, version, migrator.GetHandler())
})

```

### Anatomy of a Migration Handler

A migration handler receives the module's KV store and the application's codec. It performs three critical operations:

- **Read** legacy data structures using `store.Get` or `store.Iterator`
- **Transform** the data into the new schema
- **Write** the transformed data back to the store, deleting obsolete keys when necessary

The handler executes only when the stored module version is less than the target version specified during registration. Upon successful completion, the module's version is automatically bumped in the `VersionMap`, preventing re-execution.

### Example: Market Module Migration (v1.2.0)

The following simplified example from [`upgrades/software/v1.2.0/market.go`](https://github.com/akash-network/node/blob/main/upgrades/software/v1.2.0/market.go) demonstrates renaming a storage key:

```go
// upgrades/software/v1.2.0/market.go (simplified)
func newMarketMigration(migrator utypes.Migrator) utypes.Migration {
    return marketMigration{migrator}
}
type marketMigration struct{ utypes.Migrator }

func (m marketMigration) GetHandler() sdkmodule.MigrationHandler {
    return func(ctx sdk.Context) error {
        store := m.StoreKey().PrefixStore(ctx.KVStore())
        // Rename key "bids" → "order_bids"
        oldKey := []byte("bids")
        newKey := []byte("order_bids")
        bz := store.Get(oldKey)
        if bz != nil {
            store.Set(newKey, bz)
            store.Delete(oldKey)
        }
        return nil
    }
}

```

### Adding a New Module Migration

To implement a new migration for an upcoming Akash release:

1. Create a migration file under `upgrades/software/<next-version>/` (e.g., [`upgrades/software/v1.3.0/my_module.go`](https://github.com/akash-network/node/blob/main/upgrades/software/v1.3.0/my_module.go))
2. Implement the `NewMigrationFn` constructor and `MigrationHandler` logic
3. Register it in the version's [`init.go`](https://github.com/akash-network/node/blob/main/init.go):

```go
// upgrades/software/v1.3.0/init.go
utypes.RegisterMigration(myModule.ModuleName, 4, newMyModuleMigration)

```

4. Bump the module's version in its `AppModule` definition if necessary, ensuring the configurator recognizes the version delta.

## The Upgrade Lifecycle: From Proposal to Execution

The complete upgrade workflow orchestrates both consensus version changes and module migrations through the following sequence:

1. **Plan creation** – A `SoftwareUpgradeProposal` is submitted on-chain, specifying a target block height and upgrade name (e.g., `v1.0.0`, `v1.2.0`).
2. **Handler registration** – When nodes restart, `AkashApp.registerUpgradeHandlers()` reads the upgrade plan from disk and calls `SetUpgradeHandler` to register the appropriate handler.
3. **Store loading** – If the upgrade requires storage changes (like adding the `consensus` module), `SetStoreLoader` applies the `StoreUpgrades` configuration.
4. **Execution at height** – When the network reaches the specified block height, the `x/upgrade` module triggers the registered handler. This executes consensus parameter migrations and invokes all registered module migrations via the configurator.
5. **Post-upgrade operation** – The chain continues with the new store layout and updated module versions. Future upgrades repeat this pattern by adding new directories under `upgrades/software/`.

## Summary

- **Consensus version upgrades** migrate Tendermint core parameters from `x/params` to the dedicated `x/consensus` module, requiring store additions and deletions defined in [`upgrades/software/v1.0.0/upgrade.go`](https://github.com/akash-network/node/blob/main/upgrades/software/v1.0.0/upgrade.go).
- **Module migrations** use the `RegisterMigration` pattern in [`upgrades/types/types.go`](https://github.com/akash-network/node/blob/main/upgrades/types/types.go) to transform module-specific data, with handlers executing automatically based on version comparisons in the `VersionMap`.
- The **upgrade orchestration** occurs in [`app/upgrades.go`](https://github.com/akash-network/node/blob/main/app/upgrades.go), which reads on-disk plans and wires handlers into the Cosmos SDK's upgrade module.
- Adding new migrations requires only creating a handler implementation and registering it in the appropriate `upgrades/software/<version>/init.go` file.

## Frequently Asked Questions

### What is the difference between a consensus version upgrade and a module migration?

A **consensus version upgrade** modifies global blockchain parameters and storage structures—specifically moving Tendermint consensus params from `x/params` to `x/consensus`—while a **module migration** transforms data within a specific module (like `market` or `deployment`) from one schema version to another. Consensus upgrades affect the entire chain's configuration, whereas module migrations are scoped to individual storage namespaces.

### How do I register a new module migration for an upcoming Akash upgrade?

Create a migration file in `upgrades/software/<target-version>/` that implements the `NewMigrationFn` type and returns a `Migration` with your transformation logic. Import this in the version's [`init.go`](https://github.com/akash-network/node/blob/main/init.go) and call `utypes.RegisterMigration(moduleName, targetVersion, yourConstructor)`. Ensure the module's version constant in its source code matches the target version so the configurator triggers the migration.

### What happens if a module migration fails during an upgrade?

If a migration handler returns an error, the upgrade panics and the chain halts at the upgrade height. This safety mechanism prevents the chain from continuing with inconsistent state. Operators must investigate the failure, potentially patch the migration logic, and coordinate a restart from the last valid height before the upgrade plan was executed.

### Where are the consensus parameters stored after the v1.0.0 upgrade?

After the v1.0.0 upgrade executes, consensus parameters reside in the **`x/consensus`** module's dedicated store space, accessible via the `ConsensusParams` keeper defined in [`app/types/app.go`](https://github.com/akash-network/node/blob/main/app/types/app.go). The legacy storage in `x/params` is removed from the multistore, and the application no longer depends on the deprecated params subspace for Tendermint configuration.