Where Solidity Keeps Your Data
Every variable in a Solidity contract lives in one of three data locations, and choosing the right one affects both correctness and gas cost. Storage is the contract's permanent state, written to the blockchain and surviving between transactions. Memory is a temporary workspace that exists only while a function runs. Calldata is a special read-only area holding the arguments passed to external functions. Value types default sensibly, but every reference type — arrays, structs, strings, bytes, and mappings — must declare its location explicitly.
Cricket analogy: A cricket setup keeps three spaces: the permanent ICC scorebook, the dressing-room whiteboard used for one session, and the umpire's read-only team sheet — matching storage, memory, and calldata exactly.
Storage: The Persistent Ledger
Storage is organized as a giant key-value array of 32-byte slots, one contract-wide namespace where all state variables live. It is by far the most expensive place to write: setting a previously-zero slot with SSTORE costs about 20,000 gas, and updating an existing slot about 5,000. Because of this, well-written contracts minimize and batch storage writes. Crucially, declaring a local variable as storage creates a pointer to existing state — assigning through it mutates the real contract data, not a copy.
Cricket analogy: Storage is the official scorebook — every run written costs effort and lasts forever, so like a scorer you update it sparingly rather than paying the 20,000-gas 'ink' price of a fresh slot.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract DataLocations {
uint[] public numbers; // storage state variable
function process(uint[] calldata input) external {
// 'input' lives in calldata — read-only and cheapest
numbers = input; // copies calldata into storage
uint[] memory temp = new uint[](input.length); // memory
for (uint i = 0; i < input.length; i++) {
temp[i] = input[i] * 2;
}
uint[] storage ref = numbers; // storage pointer (alias)
ref.push(temp[0]); // mutates state directly
}
}Memory: The Temporary Scratchpad
Memory is a byte-addressable, function-scoped region that is zero-initialized at the start of each external call and discarded when the call returns. It is far cheaper than storage, which makes it the right place to build and manipulate reference types you don't need to persist — for example, constructing a temporary array with new uint[](n). Its cost is not free, though: the EVM charges for memory expansion, and that cost grows quadratically as you use more, so very large memory buffers can still become expensive.
Cricket analogy: Memory is the dressing-room whiteboard used to plan the batting order for one innings — cheap to scribble on and wiped after the match, unlike the permanent scorebook.
Rule of thumb for gas: use calldata for external parameters you only read, memory for data you need to build or mutate locally, and storage only for values that must persist between transactions. Every storage write is orders of magnitude more expensive than touching memory.
Calldata: The Read-Only Input
Calldata is the immutable, read-only region that holds the input data of a transaction or external call. Because it is read directly from the call payload and never copied, passing an external parameter as calldata is the cheapest option — and you cannot modify it, which prevents accidental mutation. For external functions whose reference-type arguments you only read, prefer calldata over memory; the compiler will even suggest it. When you need to change the data, copy it into memory first.
Cricket analogy: Calldata is the umpire's official team sheet handed in before play — you can read the lineup but cannot alter it mid-match, exactly like read-only calldata parameters.
Forgetting a data-location keyword on a reference type is a compile error, and accidentally taking a storage pointer when you meant a memory copy can silently mutate contract state. Always be explicit about which location you intend.
- Storage is persistent contract state written to the blockchain; SSTORE to a fresh 32-byte slot costs about 20,000 gas.
- Memory is a temporary, function-scoped region that is cleared when the function returns and is far cheaper than storage.
- Calldata is a read-only, non-modifiable region holding the arguments of external calls — the cheapest location because nothing is copied.
- Reference types (arrays, structs, strings, bytes, mappings) require an explicit data-location keyword in parameters and local variables.
- Assigning a storage reference creates a pointer that mutates state directly, while assigning to a memory variable copies the data.
- Mappings can only exist in storage; they cannot be declared in memory or calldata.
- Prefer calldata over memory for external parameters you don't modify to save gas.
Practice what you learned
1. Roughly how much gas does writing a value to a previously-unused storage slot (SSTORE) cost?
2. Which data location is read-only and cannot be modified inside a function?
3. What happens to a memory array when the function that declared it returns?
4. Which statement about a storage local variable is TRUE?
5. Where can a mapping be declared?
Was this page helpful?
You May Also Like
Arrays and Mappings
Arrays are ordered, iterable collections; mappings are hash-based key-value stores with O(1) lookup. Knowing their capabilities, limits, and gas costs is essential to writing safe contracts.
Structs and Enums in Solidity
Structs group related fields into custom record types, while enums give readable names to a fixed set of states — together they turn loose primitives into safe, self-documenting data models.
Gas Optimization in Solidity
How the EVM prices computation and storage, and the practical patterns, storage packing, caching, calldata, unchecked math, that reduce transaction costs without sacrificing safety.
Solidity Data Types and Value Types
Explore Solidity's value types and reference types, including sized integers, booleans, addresses, bytes, enums, arrays, structs, and mappings, and how they are copied and stored.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics