在编写模块或链之前,先理解 Cosmos SDK 如何组织代码以及各部分如何连接,会更容易上手。本页会梳理 Cosmos SDK 应用的目录结构,解释模块内部包含哪些内容,并说明模块如何组装成一个可运行的应用。

什么是 SDK 应用

Cosmos SDK 应用是一个实现确定性状态机的 Go 二进制程序。它与 CometBFT 一起运行在节点守护进程中。CometBFT 负责驱动共识,而 SDK 应用负责执行交易并维护状态。 每个 SDK 应用都由三个主要部分组成:
  • BaseApp:实现 ABCI 的执行引擎,并负责协调交易处理流程
  • Modules:封装业务逻辑、状态、消息和查询的自包含单元
  • app.go:装配层,用于实例化 BaseApp、注册模块,并在启动时配置应用
下一节会更深入地介绍 BaseApp 和 app.go。本页重点说明它们在代码库中的组织方式。若想看到这些内容如何协同工作,可以继续阅读 Build a Chain 教程系列。

仓库结构

SDK 应用仓库通常采用如下布局:
myapp/
├── app/
│   └── app.go           # Application wiring: configures BaseApp, registers modules
├── cmd/
│   └── main.go          # Node binary entrypoint
├── x/
│   ├── mymodule/        # Custom module
│   └── ...
└── proto/
    └── myapp/
        └── mymodule/
            └── v1/
                ├── tx.proto
                ├── query.proto
                ├── state.proto
                └── genesis.proto
每个目录都有明确的职责:
  • x/ 包含各个模块。每个子目录都是一个独立、自包含的模块。Cosmos SDK 内置模块(x/auth、x/bank、x/staking 等)也遵循相同的布局,并作为 Go package 引入。你的自定义模块会与它们并列存在。
  • app/ 包含 app.go,用于组装应用:创建 BaseApp、挂载存储、初始化 keeper,并通过 ModuleManager 注册所有模块。
  • cmd/ 包含 main.go,即节点二进制的入口点。它负责解析命令行参数、读取配置文件,并启动同时运行 CometBFT 节点和 SDK 应用的守护进程。
  • proto/ 包含所有自定义类型的 Protobuf 定义:消息、查询、状态结构和 genesis。Go 代码会从这些文件生成,并在整个模块中使用。Proto 文件位于仓库根目录,而不是 x/ 内部,这样便于跨语言和工具链共享。

模块内部包含什么

x/ 下的每个模块通常都遵循一致的内部布局:
x/mymodule/
├── keeper/          # Keeper (state access), MsgServer, QueryServer
├── types/           # Generated proto types, store keys, expected_keepers.go
└── module.go        # AppModule: wires the module into the application
Proto 定义位于独立的 proto/ 目录中,而不是放在 x/ 内。关于各个文件的完整说明及其作用,可参考 模块介绍。

模块如何组装成应用

模块通过 app.go 中的 ModuleManager 组装到一起。ModuleManager 持有全部已注册模块,并负责在整个应用范围内协调它们的生命周期钩子(InitGenesis、BeginBlock、EndBlock 以及服务注册)。模块执行顺序需要在 app.go 中显式配置,而且顺序很重要。例如,在 simapp 中,分发模块会在 BeginBlock 阶段先于 slashing 模块执行,以便先处理验证者奖励,再应用惩罚更新。关于 BaseApp 如何与它集成的细节,可参阅 Module Manager。 BaseApp 实现了供 CometBFT 调用的 ABCI 接口,以驱动区块执行。当 CometBFT 调用 FinalizeBlock 时,BaseApp 会让该区块依次经过各个阶段(PreBlock、BeginBlock、交易处理、EndBlock),并返回最终生成的应用哈希。关于 BaseApp 的详细说明,可参阅 BaseApp 概览。

app.go 的作用

app.go 是定义某条具体链的核心文件。应用正是在这里由各个组成部分装配起来。它通常会执行以下步骤:
  1. 使用应用名称、logger、数据库和 codec 创建一个 BaseApp 实例。
  2. 为每个模块创建 StoreKey,并将其挂载到 multistore。
  3. 实例化各个 Keeper,传入该模块依赖的 codec、store key 以及其他 keeper 的引用。
  4. 使用所有模块实例创建 ModuleManager。
  5. 配置执行顺序:指定哪些模块在 genesis、BeginBlock 和 EndBlock 阶段优先执行。
  6. 通过 ModuleManager 注册全部 gRPC 服务(消息和查询处理器)。
  7. 设置 AnteHandler 及其他中间件。
由于 app.go 本身就是普通的 Go 代码,因此它可以被完全自定义。链只包含自己需要的模块,按需将各个 keeper 连接起来,并控制所有生命周期钩子的执行顺序。

链中的其他文件

一个完整的 SDK 链仓库不仅包含 x/、app/、cmd/ 和 proto/。下面列出的是你通常还会在 Cosmos SDK 链仓库中看到的一些其他文件:

app/ 中的附加文件

在真实应用中,app/ 目录通常会拆分为多个文件,以便让 app.go 专注于装配逻辑:
app/
├── app.go          # Main wiring: BaseApp, keepers, module registration
├── export.go       # Exports current state as a genesis file (hard forks, snapshots)
├── upgrades.go     # Upgrade handlers for consensus-breaking software changes
└── genesis.go      # Helpers for genesis state initialization (optional)
  • export.go:实现 ExportAppStateAndValidators,用于将所有模块状态序列化为 genesis.json。这通常用于迁移到新的链版本(硬分叉),或基于线上链快照创建测试网。
  • upgrades.go:注册由 x/upgrade 模块消费的具名升级处理器。每个处理器只会在治理批准的升级高度对应的区块执行一次,并完成所需的状态迁移。

仓库根目录

myapp/
├── go.mod          # Go module definition: SDK version and all dependencies
├── go.sum          # Cryptographic checksums for all dependencies
├── Makefile        # Build, test, and codegen tasks
└── scripts/        # Automation scripts (proto generation, linting)
  • go.mod / go.sum:标准的 Go module 文件。go.mod 声明 Cosmos SDK 版本以及所有其他导入依赖。go.sum 为完整依赖树提供可校验的校验和。
  • Makefile:开发任务的标准入口。make build 用于编译二进制,make test 运行单元测试,make proto-gen 根据 .proto 文件重新生成 Go 代码。大多数 SDK 链还会包含 lint、仿真测试和 Docker 构建相关目标。
  • scripts/:Makefile 调用的工具脚本及其配置。

节点二进制(cmd/)

cmd/
└── myappdaemon/
    ├── main.go         # Binary entrypoint
    └── root.go         # Root Cobra command: subcommands (start, tx, query, keys, ...)
cmd/ 目录会产出节点守护进程二进制(例如 simd、gaiad、wasmd)。它使用 Cobra 暴露子命令,用于启动节点、提交交易、查询状态、管理密钥以及执行 genesis 初始化。start 命令会在单一进程中同时启动 CometBFT 和 SDK 应用。

节点主目录

一个典型仓库保存的是链的源代码。当你真正运行一个节点时,二进制会在磁盘上生成一个独立的主目录,用于保存运行时配置和链数据。执行 myappdaemon init 会创建这个目录:
~/.myapp/                  # Node home directory (configurable with --home)
├── config/
│   ├── app.toml           # SDK server configuration
│   ├── config.toml        # CometBFT configuration
│   ├── client.toml        # CLI client defaults
│   └── genesis.json       # Initial chain state
└── data/                  # Database files (block store, state store, snapshots)
默认位置是 ~/.myapp,但可以通过 --home 参数或 MYAPP_HOME 环境变量覆盖。 每个配置文件都控制节点中的不同层:
  • app.toml:SDK 层的服务端设置。用于控制是否启用 gRPC 服务和 REST API、它们的绑定地址、状态同步配置、裁剪策略以及 mempool 参数。
  • config.toml:CometBFT 层的设置。用于控制 P2P 网络(seeds、peers、监听地址)、共识超时、CometBFT RPC 服务地址以及区块大小限制。
  • client.toml:CLI 客户端命令的默认值。保存 chain ID、keyring backend 以及节点 RPC 地址,这样你就不必在每条命令里都传 --chain-id 和 --node。
  • genesis.json:链在区块 0 时的初始状态。加入网络时,它通常通过带外方式分发;对于新链,也可以在本地生成。一旦链启动后,这个文件就不会再被读取。

总结

SDK 应用是由模块组成并在 app.go 中完成装配的确定性状态机。代码库通常遵循约定式布局:模块位于 x/,应用装配逻辑位于 app/,二进制入口位于 cmd/,Protobuf 定义位于 proto/。 ModuleManager 负责装配模块,并在整个应用中协调各模块的生命周期钩子。BaseApp 提供 ABCI 实现,用于将状态机连接到 CometBFT 的共识引擎。 下一节 BaseApp 概览 会进一步解释 BaseApp 是什么,以及它如何协调交易执行。
Before writing a module or chain, it helps to understand how the Cosmos SDK organizes code and how the pieces connect. This page maps the directory structure of a Cosmos SDK application, explains what lives inside a module, and shows how modules are assembled into a running application.

What is an SDK application

A Cosmos SDK application is a Go binary that implements a deterministic state machine. It runs alongside CometBFT inside the node daemon process. CometBFT drives consensus and the SDK application executes transactions and maintains state. Every SDK application is composed of three main elements:
  • BaseApp: the execution engine that implements the ABCI and orchestrates transaction processing
  • Modules: self-contained units of business logic, state, messages, and queries
  • app.go: the wiring layer that instantiates BaseApp, registers modules, and configures the application at startup
BaseApp and app.go are covered in depth in the next two sections. This page focuses on how they are organized in the codebase. To see all of this in action, follow the Build a Chain tutorial series.

Repository structure

SDK applications repositories generally use the following layout:
myapp/
├── app/
│   └── app.go           # Application wiring: configures BaseApp, registers modules
├── cmd/
│   └── main.go          # Node binary entrypoint
├── x/
│   ├── mymodule/        # Custom module
│   └── ...
└── proto/
    └── myapp/
        └── mymodule/
            └── v1/
                ├── tx.proto
                ├── query.proto
                ├── state.proto
                └── genesis.proto
Each directory has a distinct responsibility:
  • x/ contains the modules. Each subdirectory is a separate, self-contained module. Built-in Cosmos SDK modules (x/auth, x/bank, x/staking, etc.) follow the same layout and are imported as Go packages. Your custom modules live alongside them.
  • app/ contains app.go, which assembles the application: creating BaseApp, mounting stores, initializing keepers, and registering all modules with the ModuleManager.
  • cmd/ contains main.go, the entrypoint for the node binary. It parses command-line flags, reads configuration files, and starts the daemon process that runs both the CometBFT node and the SDK application.
  • proto/ contains the Protobuf definitions for all custom types: messages, queries, state schemas, and genesis. Go code is generated from these files and consumed throughout the module. Proto files live at the repository root, not inside x/, so they can be shared across languages and tooling.

What lives inside a module

Each module under x/ follows a consistent internal layout:
x/mymodule/
├── keeper/          # Keeper (state access), MsgServer, QueryServer
├── types/           # Generated proto types, store keys, expected_keepers.go
└── module.go        # AppModule: wires the module into the application
Proto definitions live separately in proto/, not inside x/. See Intro to Modules for a complete walkthrough of each file and the role it plays.

How modules are assembled into an application

Modules are assembled through the ModuleManager in app.go. The ModuleManager holds the full set of registered modules and coordinates their lifecycle hooks (InitGenesis, BeginBlock, EndBlock, and service registration) across the application. Module ordering is configured explicitly in app.go and matters: for example, in simapp the distribution module runs before slashing in BeginBlock so validator rewards are handled before slashing updates are applied. See Module Manager for details on how BaseApp integrates with it. BaseApp implements the ABCI interface that CometBFT calls to drive block execution. When CometBFT calls FinalizeBlock, BaseApp runs the block through all its phases (PreBlock, BeginBlock, transactions, EndBlock) and returns the resulting app hash. BaseApp is covered in detail in BaseApp Overview.

The role of app.go

app.go is the single file that defines a specific chain. It is where the application is assembled from its parts. Here is a breakdown of the steps it takes:
  1. Create a BaseApp instance with the application name, logger, database, and codec.
  2. Create a StoreKey for each module and mount it to the multistore.
  3. Instantiate each Keeper, passing in the codec, store key, and references to other keepers the module depends on.
  4. Create the ModuleManager with all module instances.
  5. Configure execution ordering: which modules run first during genesis, BeginBlock, and EndBlock.
  6. Register all gRPC services (message and query handlers) through the ModuleManager.
  7. Set the AnteHandler and other middleware.
Because app.go is plain Go code, it is fully customizable. A chain includes exactly the modules it needs, wires keepers together as required, and controls the execution order of all lifecycle hooks.

Other files in a chain

A complete SDK chain repository contains more than just x/, app/, cmd/, and proto/. Below are some other files you will typically find in a Cosmos SDK chain repository:

Additional files in app/

Real-world applications typically split the app/ directory across multiple files to keep app.go focused on wiring:
app/
├── app.go          # Main wiring: BaseApp, keepers, module registration
├── export.go       # Exports current state as a genesis file (hard forks, snapshots)
├── upgrades.go     # Upgrade handlers for consensus-breaking software changes
└── genesis.go      # Helpers for genesis state initialization (optional)
  • export.go: Implements ExportAppStateAndValidators, which serializes all module state into a genesis.json. This is used when migrating to a new chain version (hard fork) or creating a testnet from a live chain snapshot.
  • upgrades.go: Registers named upgrade handlers consumed by the x/upgrade module. Each handler runs exactly once, at the block where the governance-approved upgrade height is reached, and performs any necessary state migrations.

At the repository root

myapp/
├── go.mod          # Go module definition: SDK version and all dependencies
├── go.sum          # Cryptographic checksums for all dependencies
├── Makefile        # Build, test, and codegen tasks
└── scripts/        # Automation scripts (proto generation, linting)
  • go.mod / go.sum: Standard Go module files. go.mod declares the Cosmos SDK version and all other imported packages. go.sum provides verifiable checksums for the full dependency tree.
  • Makefile: The standard entry point for development tasks: make build compiles the binary, make test runs unit tests, make proto-gen regenerates Go code from .proto files. Most SDK chains include targets for linting, simulation tests, and Docker builds.
  • scripts/: Shell scripts and configuration for tooling that the Makefile invokes.

The node binary (cmd/)

cmd/
└── myappdaemon/
    ├── main.go         # Binary entrypoint
    └── root.go         # Root Cobra command: subcommands (start, tx, query, keys, ...)
The cmd/ directory produces the node daemon binary (e.g., simd, gaiad, wasmd). It uses Cobra to expose subcommands for starting the node, submitting transactions, querying state, managing keys, and running genesis initialization. The start command spins up CometBFT and the SDK application together in a single process.

Node home directory

A typical repository contains the source code for a chain. When you actually run a node, the binary generates a separate home directory on disk that holds runtime configuration and chain data. Running myappdaemon init creates this directory:
~/.myapp/                  # Node home directory (configurable with --home)
├── config/
│   ├── app.toml           # SDK server configuration
│   ├── config.toml        # CometBFT configuration
│   ├── client.toml        # CLI client defaults
│   └── genesis.json       # Initial chain state
└── data/                  # Database files (block store, state store, snapshots)
The location defaults to ~/.myapp but can be overridden with the --home flag or the MYAPP_HOME environment variable. Each configuration file controls a distinct layer of the node:
  • app.toml: SDK-level server settings. Controls whether the gRPC server and REST API are enabled, their bind addresses, state sync configuration, pruning strategy, and mempool parameters.
  • config.toml: CometBFT-level settings. Controls P2P networking (seeds, peers, listen address), consensus timeouts, the CometBFT RPC server address, and block size limits.
  • client.toml: Default values for CLI client commands. Stores the chain ID, keyring backend, and the node RPC address so you don’t have to pass --chain-id and --node on every command.
  • genesis.json: The initial state of the chain at block 0. It is distributed out-of-band when joining a network, or generated locally for a new chain. Once the chain starts, this file is no longer read.

Summary

An SDK application is a deterministic state machine composed of modules assembled in app.go. The codebase follows a conventional layout: modules in x/, application wiring in app/, the binary entrypoint in cmd/, and Protobuf definitions in proto/. The ModuleManager assembles modules and coordinates their lifecycle hooks across the application. BaseApp provides the ABCI implementation that connects the state machine to CometBFT’s consensus engine. The next section, BaseApp Overview, explains what BaseApp is and how it coordinates transaction execution in detail.