100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

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.

Storage & Data StructuresIntermediate8 min readJul 10, 2026
Analogies

As contracts grow, passing around loose variables becomes error-prone. A struct is a user-defined composite type that bundles several related variables — of possibly different types — under a single name, much like a record or object in other languages. Structs make data models explicit: instead of three parallel arrays for names, ages, and wallets, you define one Person type and work with whole records. Structs can be nested, stored in arrays, and used as mapping values.

🏏

Cricket analogy: A struct is like a player's full profile card bundling name, batting average, and jersey number into one record, just as Solidity groups related fields into a single custom type.

Defining and Using Structs

You declare a struct once, then instantiate it either in memory (for temporary assembly) or directly in storage. A common pattern is to build a memory struct with named fields, then push it into a storage array or assign it to a mapping in a single copy. To modify a stored record in place, take a storage pointer to it — Person storage p = people[i]; — and write to p.age; that change hits contract state directly. A memory copy, by contrast, is discarded when the function returns.

🏏

Cricket analogy: Taking a storage pointer to change a player's score is like editing the live scoreboard entry directly, whereas a memory copy is like updating a printed team sheet that never touches the official record.

solidity
pragma solidity ^0.8.20;

contract Registry {
    struct Person {
        string name;
        uint age;
        address wallet;
    }

    Person[] public people;
    mapping(address => Person) public byWallet;

    function add(string calldata _name, uint _age) external {
        Person memory p = Person({name: _name, age: _age, wallet: msg.sender});
        people.push(p);          // copy memory struct into storage array
        byWallet[msg.sender] = p;
    }
}

Structs and enums are compile-time constructs and add no runtime type information. An enum is really just a uint8, so State.Locked is stored on-chain as the number 1, keeping enum-typed state variables cheap.

Enums: Named Constants for State

An enum defines a small, fixed set of named constants, giving readable names to what would otherwise be magic numbers. Under the hood an enum is a uint8, so it can hold at most 256 members and each member maps to an integer starting at 0. An uninitialized enum variable therefore defaults to its first member. Enums shine for modelling state machines — enum State { Created, Locked, Released, Refunded } — because functions can require a specific state before transitioning, and any attempt to assign an out-of-range value reverts.

🏏

Cricket analogy: An enum is like a match's phase — Toss, InPlay, InningsBreak, Result — a fixed set of named stages defaulting to the first, just as a Solidity enum defaults to value 0.

solidity
contract Escrow {
    enum State { Created, Locked, Released, Refunded }
    State public state; // defaults to State.Created (value 0)

    function lock() external {
        require(state == State.Created, "bad state");
        state = State.Locked;
    }
}

Structs and Enums Together

Structs and enums are frequently combined: an order record might be a struct whose fields include an enum status, giving each record a controlled, readable state. Keep the constraints in mind — a struct that contains a mapping can only exist in storage and cannot be built in memory or returned by value, and converting a raw integer into an enum outside its valid range reverts. Used well, the pair turns sprawling primitive variables into self-documenting, safer data models.

🏏

Cricket analogy: Just as you can't take the live DRS review system home on a printed sheet, a struct containing a mapping can't be built in memory — mappings only live in storage.

A struct that contains a mapping can never be created in memory or returned from a function; it must live in storage. Also, casting an integer outside an enum's defined range reverts, so validate inputs before converting them to an enum.

  • A struct is a user-defined composite type that groups related variables of different types under one name.
  • Structs can be stored in mappings and arrays and are commonly built in memory before being copied to storage.
  • An enum is a user-defined type of named constants backed by uint8, so it supports at most 256 members.
  • An enum variable defaults to its first member (integer value 0) when uninitialized.
  • Assigning an out-of-range integer to an enum reverts, making enums safe for state machines.
  • A struct containing a mapping can only exist in storage and cannot be constructed in memory.
  • Accessing a struct in storage via a pointer lets you mutate individual fields directly.

Practice what you learned

Was this page helpful?

Topics covered

#Programming#SolidityStudyNotes#StructsAndEnumsInSolidity#Structs#Enums#Solidity#Grouping#StudyNotes#SkillVeris#ExamPrep