DEV Community


Posted on • Updated on


Solidity Data Storage Location

When we declare dynamic data types we need to specify the location to store them. Dynamic data types in Solidity are arrays, strings, struct etc. One of three locations of storage, memory and calldata are usually specified.

Using storage as a location means the data is stored on the blockchain while memory means the data is saved in memory and will be erased after the function in which it was declared has finished executing. The other location of calldata is used to stored variable that is passed as an input parameter to a function.

 //SPDX-License-Identifier: Unlicense
pragma solidity >=0.7.0 <0.9.0;

contract StorageLocation {
    Person[] public persons;

    struct Person {
        string name;
        uint age;
        address personAddress;

    constructor() {
       Person memory newperson = Person({
           name: "Jamie",
           age: 33,
           personAddress: msg.sender

       Person memory personTwo = Person({
           name: "Bones Man",
           age: 33,
           personAddress: msg.sender

    function loadPerson() public view returns ( Person[] memory ){
        return persons;

    function changeDataone() public view {
        Person memory person = persons[0];
        person.age = 56;

    function changeDataTwo() public {
        Person storage person = persons[0];
        person.age = 76;

    function receiveAsCallData(uint256[] calldata a) public {
        //you can not modify a
Enter fullscreen mode Exit fullscreen mode

The smart contract above is a simple smart contract. At the top of the smart contract we defined an array of Person which is a user defined struct. The array of Person is stored in a variable called persons. The persons variable is stored on the blockchain because it is a state variable so therefore, it's location is storage.

Looking at the constructor function and you will see that there are two Person type created and pushed into the Person[] array called persons. The newperson variable inside the constructor is saved in memory and will be destroyed after the constructor function has finished running. After creating the newperson struct it was pushed into the persons array for permanent storage. The temporary newperson variable in memory will be discarded after the constructor function finish executing.

Take a close look at both the changeDataone function and the changeDataTwo.You will notice that changeDataone function creates a variable named person and saved it to memory.

Person memory person = persons[0];
Doing it this way reads the data of the persons array at index of 0 and stores it in a person variable in memory. Attempting to change person.age to 56 will not be successful because we are not referencing the storage location of persons. At the termination of the function the persons storage variable remains the same because the data in memory has be wiped off.

To persist the changes we make in a dynamic data type we must reference the storage location of that variable. The function changeDataTwo does that. Try it out on Remix

When the contract is deployed, two Person struct is added to the persons array via the constructor which you can view by running loadPerson. Run the function changeDataone and observe if the first Person struct changed as explained. Then run the function changeDataTwo and you will notice that the persons variable was updated.

The third location calldata is used to pass input parameters to functions. Storing a variable in calldata means that the variable cannot be modified. Using calldata has the potential of saving some gas as the EVM does not copy over the data stored on it as it does when you used memory as a location.


You make use of memory location when you want to read a dynamic data stored in state without modification or you need a temporary store for a dynamic data type.

You make use of storage when you want a reference to the dynamic data stored in state for the purpose of modification.

If you won't be changing the value of the dynamic data type passed as input to a function, you can make use of calldata. Usingcalldata helps to save gas because the EVM does not do a copy of the data.

Top comments (0)