How to Use Mappings Inside Structs in Solidity

A mapping can live inside a Solidity struct when the struct stays in storage. That layout lets one record hold ordinary fields such as a name plus values keyed by addresses, but it also changes what you can copy or return from a function. I compiled the contract below with solc during this refresh, so the example starts from a contract artifact rather than a sketch.

The storage rule behind a mapping in a struct

A mapping is a key-to-value lookup that Solidity stores persistently. Unlike an array, it has no length and Solidity does not keep a list of its keys for you to loop through.

Solidity allows a mapping as a struct member, including a struct reached through another mapping. The restriction is the important part: mappings and structs that contain them belong in storage, not memory, because Solidity cannot create an independent in-memory copy of an unbounded key space. The Solidity Types documentation also limits public function parameters and returns to ABI-safe types.

struct Member { string name; mapping(address => uint256) credits; }

Each Member can keep a different credit amount for every address because the state mapping supplies the storage location for the struct.

A working mapping-inside-struct contract

The contract below stores one Member for each caller, with a credits mapping owned by that record.

// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract MemberCredits { struct Member { string name; mapping(address => uint256) credits; } mapping(address => Member) private members; function setName(string calldata name) external { members[msg.sender].name = name; } function setCredit(address account, uint256 amount) external { members[msg.sender].credits[account] = amount; } function getMember(address owner, address account) external view returns (string memory name, uint256 credit) { Member storage member = members[owner]; return (member.name, member.credits[account]); } }
Terminal output showing MemberCredits.sol compile successfully with solc
The MemberCredits contract compiles with solc and produces a bytecode file.

Read and write the nested mapping

setCredit reaches the record with members[msg.sender], then writes through credits[account]. An unset key reads as the value type’s default, which is 0 for uint256.

getMember takes a storage reference to the outer record and returns its name with one nested value. That result is compatible with the application binary interface (ABI).

What Solidity cannot return or copy

You cannot return a Member value that includes its mapping, and you should not expect a mapping-containing struct to behave like a normal memory object. A mapping has no enumerable key collection, so there is no complete value for the ABI encoder to serialize.

function broken(address owner) external view returns (Member memory) { return members[owner]; }

Expose a specific lookup, a scalar summary, or a separate key list when callers need enumeration. A key list adds storage and update work, so use it only when the contract must discover every key rather than inspect a known one.

Return a summary instead

getMember accepts the inner key as an input and returns only values that the ABI can encode.

function getCredit(address owner, address account) external view returns (uint256) { return members[owner].credits[account]; }

When to use this layout

Use a mapping inside a struct when each parent record needs its own keyed collection. Membership flags, per-user balances, permissions, and per-project settings are common fits because the caller usually knows both the parent and inner key.

Choose a different layout when the contract must enumerate every entry on-chain or return the complete collection to a frontend. A separate array of keys can support enumeration, but validate how duplicate prevention and deletion affect gas before adding it.

Next step

Compile the contract, deploy it in a local test environment, then call setCredit and getMember with the same owner and account addresses. That small test verifies the storage path that matters: owner, Member record, and the nested mapping entry.

Can a Solidity struct contain a mapping?

Yes. A Solidity struct can contain a mapping when the struct is used in storage. The mapping cannot be copied into memory or returned as part of a struct through the ABI.

Why can I not return a struct with a mapping in Solidity?

A mapping has no enumerable key list and is storage-only. Solidity cannot serialize the complete mapping through the ABI, so return scalar fields or a lookup result instead.

Aneesha S
Aneesha S

Aneesha S writes practical guides to MongoDB, Mongoose, and Node.js. Her articles cover document queries and updates, file operations, and HTTP requests.

Articles: 169