home / skills / multiversx / mx-ai-skills / mvx_project_architecture
This skill provides production-grade MultiversX project structure patterns, enabling clean trait-based contract design, modular modules, and safer upgrades.
npx playbooks add skill multiversx/mx-ai-skills --skill mvx_project_architectureReview the files below or copy the command above to add this skill to your agents.
---
name: mvx_project_architecture
description: Production-grade project structure patterns for MultiversX smart contracts.
---
# MultiversX Project Architecture
## Single Contract Structure
```
my-contract/
├── Cargo.toml
├── src/
│ ├── lib.rs # #[contract] trait — ONLY trait composition + init/upgrade
│ ├── storage.rs # All #[storage_mapper] definitions
│ ├── views.rs # All #[view] endpoints
│ ├── config.rs # Admin configuration endpoints
│ ├── events.rs # #[event] definitions
│ ├── validation.rs # Input validation helpers
│ ├── errors.rs # Static error constants
│ └── helpers.rs # Pure business logic functions
├── meta/
├── wasm/
└── tests/
```
## lib.rs Pattern: Trait Composition Only
```rust
#![no_std]
multiversx_sc::imports!();
#[multiversx_sc::contract]
pub trait MyContract:
storage::StorageModule
+ config::ConfigModule
+ views::ViewsModule
+ events::EventsModule
+ validation::ValidationModule
+ helpers::HelpersModule
{
#[init]
fn init(&self) { }
#[upgrade]
fn upgrade(&self) { }
#[endpoint]
fn main_operation(&self) {
self.validate_payment(&payment);
let mut cache = cache::StorageCache::new(self);
self.process_operation(&mut cache, &payment);
}
}
```
## errors.rs Pattern
```rust
pub static ERROR_NOT_ACTIVE: &[u8] = b"Contract is not active";
pub static ERROR_INVALID_AMOUNT: &[u8] = b"Invalid amount";
pub static ERROR_UNAUTHORIZED: &[u8] = b"Unauthorized";
pub static ERROR_ZERO_AMOUNT: &[u8] = b"Amount must be greater than zero";
```
## Naming Conventions
| Item | Convention | Example |
|---|---|---|
| Contract crate | kebab-case | `liquidity-pool` |
| Module files | snake_case | `storage.rs` |
| Storage keys | camelCase | `"totalSupply"` |
| Error constants | SCREAMING_SNAKE | `ERROR_INVALID_AMOUNT` |
| Module traits | PascalCase | `StorageModule` |
| Endpoint names | snake_case | `fn deposit_tokens(&self)` |
| View names | camelCase (ABI) | `#[view(getBalance)]` |
## When to Create Common Workspace Crate
Same struct/math/errors/events in 2+ contracts → move to `common/` crate.
This skill documents production-grade project structure patterns for building MultiversX smart contracts. It prescribes a clear file layout, lib.rs responsibilities, naming conventions, and when to extract shared crates. The goal is consistency, testability, and safe upgrade paths for contracts.
The guide splits contract code into focused modules: a minimal lib.rs that composes trait modules, dedicated files for storage, views, config, events, validation, errors, and helpers, plus separate meta, wasm, and test folders. It enforces lib.rs as trait composition only (init/upgrade/entrypoints call into modules) and centralizes static error strings and naming rules to avoid ambiguity. When multiple contracts share identical logic, it recommends extracting that code into a common workspace crate.
Why keep lib.rs minimal?
Minimizing lib.rs reduces coupling, makes upgrades safer, and forces implementation details into testable modules.
When should I create a common crate?
If the same structs, math, errors, or events appear in two or more contracts, extract them to a shared crate to avoid duplication and ensure consistency.