Solang and Soroban Rust SDK Differences
This page documents how Solang represents Solidity contracts on Soroban, and how that representation differs from common patterns used by the Soroban Rust SDK.
It focuses on data representation and storage layout.
For Solidity-facing language differences such as authorization syntax or Soroban storage class keywords, see Soroban Solidity Language Compatibility.
Summary
Solang and the Soroban Rust SDK target the same platform, but they do not necessarily use the same internal representations.
On Soroban, Solang uses a compiler-defined storage model for Solidity state. Arrays, structs, and nested values are lowered according to Solang’s code generation strategy, not according to any Rust SDK storage convention. Developers should rely on documented Solang behavior and should not assume raw storage compatibility with handwritten Rust SDK contracts unless that layout is explicitly documented.
Storage Layout Overview
Solang does not use EVM slot packing on Soroban. Instead, it lowers Solidity state into Soroban storage using compiler-defined keys and Soroban host values.
The right mental model is:
Soroban storage classes choose the ledger namespace: persistent, temporary, or instance
Solang chooses how a Solidity variable, struct field, or array element is represented within that storage
documented Solang behavior is what developers should rely on, not assumptions about a Rust SDK contract’s internal layout
Arrays in Storage
For arrays of native value types, Solang uses a VecObject-backed storage model.
In current Soroban code generation, storage array operations:
load the stored
VecObjecthandle from contract storageapply the relevant vector operation
write the resulting handle back to storage
This is closer to Soroban’s host vector model than to EVM-style contiguous slot arithmetic.
Relevant examples and implementation references:
Structs in Storage
Struct storage is also Soroban-specific.
Rather than packing a whole struct into a single EVM-like storage region, Solang encodes struct fields as Soroban values and stores fields separately under composite keys derived from the struct’s storage slot and field position.
As a consequence:
reading a single field can be relatively direct
reading a whole struct requires loading each stored field and reconstructing the struct in memory
full-struct loads are more expensive than field-level access
Relevant examples:
Nested Values and Composite Keys
Arrays of custom types, including arrays of structs, follow a sparse storage approach.
The important point is that nested values are not stored like flat EVM slot ranges. Instead, the storage key tracks access structure. In current Solang Soroban support, that means:
the first part of the key identifies the Solidity storage slot
later parts of the key identify field positions or indexes within the nested access path
This layout is chosen to make nested mutation practical on Soroban, but it also means developers should not assume Rust SDK-like or EVM-like key shapes unless Solang explicitly documents them.
What Developers Should Not Assume
When comparing Solang with handwritten Rust SDK contracts, developers should not assume:
identical raw storage keys
identical internal layouts for arrays, structs, or nested values
safe direct reads or writes across Solidity and Rust contracts at the raw storage level unless the layout is explicitly documented
For the current target status and support matrix, see Soroban Support Matrix.