Synopsis
Modules define most of the logic of Cosmos SDK applications. Developers compose modules together using the Cosmos SDK to build their custom application-specific blockchains. This document outlines the basic concepts behind SDK modules and how to approach module management.
Module Concepts
Deep dive into how modules work — keepers, message handlers, query services, and the module manager.
Build a Module
Follow a step-by-step tutorial to build a custom module from scratch on an example Cosmos SDK chain.
Design Considerations
Before writing any code, these are the key design decisions that shape how a module will behave, interoperate, and evolve.Define clear module boundaries
A module should own a single, well-scoped piece of application state. Resist the temptation to bundle unrelated functionality into one module because it is convenient. Narrow modules are easier to audit, re-use across chains, and upgrade independently. Ask: could a different chain reasonably use this module without modification? If the answer depends on removing half the features, the module is probably doing too much.Plan your state structure early
EveryKVStore key your module defines is permanent: removing or renaming keys requires a migration. Use the Collections library for structured state management, and name keys to be collision-resistant and self-documenting.
Consider what your module needs to index. A value that is only ever looked up by a single key is simple. A value looked up by multiple dimensions (e.g. by owner and by ID) requires secondary indexes, which add complexity and storage overhead.
Design your message and query surface
Keep theMsg service minimal. Every message your module accepts becomes part of your public API and must be handled across upgrades. Prefer fewer, general-purpose messages over many narrow ones.
Queries are cheaper to add later than messages, but consider what clients need from day one. Poorly designed queries often lead to excessive on-chain state that exists solely to support a query no one else needs.
Decide how privileged operations are controlled
Most modules have parameters that governance should be able to update. Use the standardMsgUpdateParams pattern with an Authority field, and set that authority to the governance module address at genesis. This ensures parameter changes go through on-chain governance rather than being hardcoded or requiring a chain upgrade.
If your module needs to call into another module’s privileged functions, establish those permissions through keeper references at app initialization — not through dynamic lookups at runtime.
Model inter-module dependencies carefully
List every other module your module needs access to. Each dependency becomes a keeper reference injected into your keeper at construction. Avoid circular dependencies: if module A needs B and B needs A, one of them is doing too much. Introduce a third module or restructure the shared logic. Prefer accepting interfaces over concrete keeper types. This makes your module testable in isolation and re-usable across chains with different module implementations.Plan for upgrades from the start
If your module defines state, it will eventually need a migration. Write migration logic inx/<module>/migrations/ from the first version, even if v1 to v2 is a no-op. Establish the pattern early so upgrades are not an afterthought.
See Module Upgrades for implementation details.
Role of Modules in a Cosmos SDK Application
The Cosmos SDK can be thought of as the Ruby-on-Rails of blockchain development. It comes with a core that provides the basic functionalities every blockchain application needs, like a boilerplate implementation of the ABCI to communicate with the underlying consensus engine, amultistore to persist state, a server to form a full-node and interfaces to handle queries.
On top of this core, the Cosmos SDK enables developers to build modules that implement the business logic of their application. In other words, SDK modules implement the bulk of the logic of applications, while the core does the wiring and enables modules to be composed together. The end goal is to build a robust ecosystem of open-source Cosmos SDK modules, making it increasingly easier to build complex blockchain applications.
Cosmos SDK modules can be seen as little state-machines within the state-machine. They generally define a subset of the state using one or more KVStores in the main multistore, as well as a subset of message types. These messages are routed by one of the main components of Cosmos SDK core, BaseApp, to a module Protobuf Msg service that defines them.
As a result of this architecture, building a Cosmos SDK application usually revolves around writing modules to implement the specialized logic of the application and composing them with existing modules to complete the application. Developers will generally work on modules that implement logic needed for their specific use case that do not exist yet, and will use existing modules for more generic functionalities like staking, accounts, or token management.
Modules as super-users
Modules have the ability to perform actions that are not available to regular users. This is because modules are given sudo permissions by the state machine. Modules can reject another modules desire to execute a function but this logic must be explicit. Examples of this can be seen when modules create functions to modify parameters:How to Approach Building Modules as a Developer
While there are no definitive guidelines for writing modules, here are some important design principles developers should keep in mind when building them:- Composability: Cosmos SDK applications are almost always composed of multiple modules. This means developers need to carefully consider the integration of their module not only with the core of the Cosmos SDK, but also with other modules. The former is achieved by following standard design patterns outlined here, while the latter is achieved by properly exposing the store(s) of the module via the
keeper. - Specialization: A direct consequence of the composability feature is that modules should be specialized. Developers should carefully establish the scope of their module and not batch multiple functionalities into the same module. This separation of concerns enables modules to be re-used in other projects and improves the upgradability of the application. Specialization also plays an important role in the object-capabilities model of the Cosmos SDK.
- Capabilities: Most modules need to read and/or write to the store(s) of other modules. However, in an open-source environment, it is possible for some modules to be malicious. That is why module developers need to carefully think not only about how their module interacts with other modules, but also about how to give access to the module’s store(s). The Cosmos SDK takes a capabilities-oriented approach to inter-module security. This means that each store defined by a module is accessed by a
key, which is held by the module’skeeper. Thiskeeperdefines how to access the store(s) and under what conditions. Access to the module’s store(s) is done by passing a reference to the module’skeeper.
Main Components of Cosmos SDK Modules
Modules are by convention defined in the./x/ subfolder (e.g. the bank module will be defined in the ./x/bank folder). They generally share the same core components:
- A
keeper, used to access the module’s store(s) and update the state. - A
Msgservice, used to process messages when they are routed to the module byBaseAppand trigger state-transitions. - A query service, used to process user queries when they are routed to the module by
BaseApp. - Interfaces, for end users to query the subset of the state defined by the module and create
messages of the custom types defined in the module.
AppModule interface in order to be managed by the module manager.