In the Ethereum Virtual Machine (EVM), storage refers to the persistent, contract-level key-value store used to hold state variables across contract calls and transactions. It is one of the three primary data locations in Solidity, alongside memory (temporary, function-level) and calldata (read-only input data).
At the EVM level, a fourth data location called transient storage was introduced in EIP-1153. It allows for temporary, transaction-scoped storage that is cleared when a transaction completes. As of Solidity v0.8.30, transient storage is accessible via the transient
keyword for value types (e.g., uint256
, bool
). Support for reference types (like arrays, mappings, and structs) is not yet available but is expected in future compiler releases. Until then, low-level inline assembly remains the primary way to interact with transient storage.
Unlike memory or calldata, storage persists across transactions and is not automatically cleared. All data written to storage becomes part of the contract’s state and is stored on-chain. While this data is durable, it is modifiable and can be cleared using operations like delete
or by setting its values to zero.
Incorrect handling of storage references, especially with structs, arrays, or within functions that use storage
pointers, can result in unintended overwrites or shared references, leading to subtle and difficult-to-detect bugs.
The primary function of storage is to persist contract state between function calls and transactions. State variables declared at the contract level (e.g., uint public counter
, mapping(address => uint) balances
) are placed in storage by default, making it the backbone for maintaining long-term data such as balances, configuration, and ownership.
delegatecall
(including libraries compiled with delegatecall
), the code executes in the context of the calling contract’s storage layout. It can read from and write to the caller’s storage layout, a powerful but potentially dangerous mechanism. If storage layouts are misaligned, severe bugs or vulnerabilities can be introduced, especially in upgradeable proxy patterns.Storage finds extensive use across various smart contract scenarios:
mapping(address => uint256)
.Here’s a quick comparison of EVM data locations:
Property | Storage | Memory | Calldata | Transient storage |
---|---|---|---|---|
Modifiability | Mutable | Mutable | Immutable (read-only) | Mutable |
Lifespan | Persistent (on-chain) | Temporary (during a message call) | Temporary (during a message call) | Temporary (during a transaction) |
Gas cost | High | Moderate | Low | Low to moderate |
Primary use | Long-term contract state | In-function computation | Function arguments for external calls | Temporary cross-functional data |
contract StorageExample {
uint256 public value; // stored at slot 0
mapping(address => uint256) public balances; // storage slot determined by keccak256(abi.encode(key, slot))
function store(uint256 _val) external {
value = _val; // Writes to storage slot 0
}
function updateBalance(address _user, uint256 _amount) external {
balances[_user] = _amount; // Writes to slot: keccak256(abi.encode(_user, uint256(1)))
}
}
In the example above:
value
is stored at slot 0.balances[_user]
is stored at keccak256(abi.encode(_user, 1))
, where 1 is the slot assigned to the balances
mapping declaration. Slot 1 does not directly store data but serves as the base slot for the mapping. Solidity uses this “root” slot to compute unique keys for each mapping entry via a hash formula, ensuring deterministic and collision-free storage layout. This layout is critical when analyzing storage structure to avoid storage collisions in upgradeable contracts or when accessing storage directly via assembly.Storage is a persistent, modifiable, contract-level data location in the EVM. It is used to maintain a long-term state across transactions, such as balances, configurations, and ownership records. While it comes with high gas costs, its permanence and determinism are foundational to contract behavior and user trust.
Cyfrin Updraft can help you master how and when to use storage to build reliable, stateful, upgrade-safe smart contracts.