About this tool
What this visualizer answers
The Solidity Storage Layout Visualizer shows how the compiler will pack your contract's state variables into 32 byte storage slots. Use it to plan upgradeable contract layouts, find gas wasted on poorly ordered variables, and derive the storage slot for any mapping key without running a forge or hardhat command.
The tool models the standard Solidity packing rules: variables fill slots in declaration order, fit into the current slot if there is room, and start a new slot if not. Dynamic types (string, bytes, mappings, dynamic arrays) reserve a full slot for length or hash anchor and place actual data elsewhere via keccak256.
How to use it
Add each state variable in the order your contract declares them. Pick the type from the dropdown. As you build the list, the slot table updates to show which variables share slots and which slots have unused bytes. The unused byte indicator surfaces packing opportunities.
For mapping value slots, use the calculator at the bottom. Enter the slot where the mapping is declared and the key in 32 byte hex form. The tool returns the keccak256 derived value slot, the same one your contract reads or writes when accessing mapping[key].
How storage packing works
EVM storage is a key value store of 32 byte slots. The Solidity compiler assigns each state variable a slot starting from 0, in declaration order. Static variables smaller than 32 bytes pack into the current slot if they fit, otherwise start a new one. Dynamic variables always start a new slot and store data elsewhere using keccak256 derivations.
Mapping values live at keccak256(abi.encode(key, slot)). Dynamic array items live at keccak256(slot) plus the index. Strings and bytes use a length flag in the slot and store the data at keccak256(slot) when long enough to overflow the slot itself.
Where storage layout most often surprises engineers
The first surprise is that ordering matters. A contract with three uint128 variables uses two slots if the first follows a uint256, but only two if all three are declared consecutively. Reorder when reviewing the visualizer output and watch the slot count drop.
The second surprise is upgradeable contracts. Adding a variable in the middle of an inheritance chain shifts every subsequent variable into a different slot. Existing on chain data continues to live at the original slot, so the new code reads garbage. OpenZeppelin's __gap pattern reserves trailing slots so additions are safe.
When this tool is the right one and when it is not
Use this visualizer for design and review work: planning a new contract's state, auditing a fork before changes, teaching storage layout in a workshop, or sanity checking what slot a mapping value lives at when reading raw storage with cast or eth_getStorageAt.
For the source of truth on a deployed contract, run forge inspect ContractName storageLayout in Foundry, or compile with Hardhat and inspect the artifact. Those commands account for inheritance, libraries, and any compiler version specific behaviour that this planning tool does not model.
Designing an upgradeable system?
Storage layout is one of the most common reasons upgradeable contracts go wrong in production. Bring the design for a focused review.
Book a smart contract reviewFrequently asked questions
- How do I optimise Solidity storage for gas?
- Order small variables consecutively so they share a 32 byte slot, since every slot write costs real gas. uint128 plus uint128 fits in one slot. address with 20 bytes plus bool with 1 byte plus uint64 with 8 bytes also fits. Avoid placing a uint256 between two small variables because the small ones get pushed into separate slots. Booleans are a particularly common waste since each occupies a full byte in storage.
- What is Solidity storage layout?
- Solidity storage layout is the mapping from declared state variables to 32 byte storage slots in the EVM. Each slot costs gas to read or write. Solidity packs multiple smaller variables into one slot when they are declared consecutively. Bad ordering leaves slots half empty and adds slot reads, which costs real gas at scale. Layout also matters for upgradeable contracts because adding or reordering variables changes which slot existing data lives in.
- How does Solidity decide what to pack into storage slots?
- Solidity packs state variables in declaration order. If the next variable fits in the remaining bytes of the current slot, it joins. Otherwise it starts a new slot. Dynamic types such as string, bytes, mappings, and dynamic arrays always start a new slot and reserve the full 32 bytes because their actual data lives elsewhere in storage at a derived location.
- How is the mapping slot computed in Solidity using keccak256?
- For a mapping declared at slot N and key K, the value slot is keccak256(abi.encode(K, N)). The mapping calculator in this tool exposes the derivation. Address keys must be padded to 32 bytes. Integer keys are encoded as uint256. This is the same derivation that Solidity uses internally every time you read or write mapping[key], which is why every Solidity engineer should know it.
- How does EVM storage packing work for nested mappings?
- For mapping(K1 => mapping(K2 => V)) declared at slot N, the inner mapping for outer key K1 starts at keccak256(abi.encode(K1, N)). The value for K2 inside that inner mapping is then keccak256(abi.encode(K2, keccak256(abi.encode(K1, N)))). Apply the formula recursively for any depth. The cost is one keccak256 per level of nesting at read time.
- What is __gap and why do upgradeable contracts use it for storage?
- OpenZeppelin's upgradeable base contracts include uint256[50] private __gap at the end of each contract. The reserved slots let future versions add variables without colliding with downstream contracts that inherit from them. The pattern is essential when shipping UUPS or Transparent proxy contracts where storage layout collisions break the deployed state in ways that are hard to recover.
- Does this Solidity storage visualizer compile real contracts?
- No. The tool models the layout based on the variable list you enter, applying the standard Solidity packing rules. For real compiler output, run forge inspect ContractName storageLayout in Foundry, or hardhat compile with the --storage-layout flag in Hardhat. This visualizer is for planning, teaching, and quick verification, not the source of truth for a deployed contract.
Related services and reading
From layout to gas optimisation.