# What Are the Allowed Storage Types in GenLayer Intelligent Contracts?

> GenLayer intelligent contracts support five deterministic storage types including TreeMap DynArray Array u256 i256 and custom classes. Learn more about these powerful options.

- Repository: [GenLayer Labs/genlayer-project-boilerplate](https://github.com/genlayerlabs/genlayer-project-boilerplate)
- Tags: how-to-guide
- Published: 2026-08-20

---

**GenLayer intelligent contracts support five deterministic storage types: `TreeMap`, `DynArray`, `Array`, `u256`/`i256`, and `@allow_storage`-decorated custom classes.**

These types ensure that smart contract state can be reproduced identically across all validator nodes in the GenLayer network. The `genlayer-project-boilerplate` repository documents these constraints in [`CLAUDE.md`](https://github.com/genlayerlabs/genlayer-project-boilerplate/blob/main/CLAUDE.md) and enforces them through the GenVM linter, which blocks nondeterministic Python data structures like standard `dict` and `list`.

## Core Storage Types for GenLayer Contracts

GenLayer's storage system replaces Python's native collections with deterministic alternatives. Each type is optimized for specific access patterns while maintaining the reproducibility required for consensus.

### TreeMap: Deterministic Ordered Mapping

`TreeMap[Key, Value]` provides **O(log n)** lookups with guaranteed insertion order. Unlike Python's `dict`, this structure produces identical iteration order on every node.

Use `TreeMap` for any key-value data that persists across blocks:

```python
from genlayer import *

class Token(gl.Contract):
    balances: TreeMap[Address, u256]

    def __init__(self):
        self.balances = TreeMap()

    @gl.public.write
    def transfer(self, to: Address, amount: u256):
        sender = gl.message.sender_address
        self.balances[sender] -= amount
        self.balances[to] = self.balances.get(to, u256(0)) + amount

```

### DynArray: Growable Deterministic Lists

`DynArray[Element]` supports dynamic sizing with predictable ordering. Use this when your collection needs to expand or contract during contract execution.

Typical applications include participant registries and pending transaction queues:

```python
from genlayer import *

class Registry(gl.Contract):
    participants: DynArray[Address]

    def __init__(self):
        self.participants = DynArray()

    @gl.public.write
    def join(self):
        self.participants.append(gl.message.sender_address)

```

### Array: Fixed-Size Collections

`Array[Element]` requires compile-time length knowledge. This constraint enables memory optimizations and guarantees stable indexing.

Best for leaderboards, round-robin slots, or other bounded collections:

```python
from genlayer import *

class Leaderboard(gl.Contract):
    top_scores: Array[u256]  # Exactly 10 entries

    def __init__(self):
        self.top_scores = Array([u256(0)] * 10)

```

### u256 and i256: Native Integer Types

These 256-bit integers replace Python's arbitrary-precision `int` for deterministic arithmetic. **u256** handles unsigned values; **i256** handles signed.

Always use these types for counters, balances, timestamps, and mathematical operations:

```python
from genlayer import *

class Counter(gl.Contract):
    value: u256
    signed_delta: i256

    def __init__(self):
        self.value = u256(0)
        self.signed_delta = i256(-5)

```

## Creating Custom Storage Types with @allow_storage

The `@allow_storage` decorator extends the type system to user-defined classes. Decorated classes must contain **only allowed storage primitives** internally.

This pattern appears in [`contracts/football_bets.py`](https://github.com/genlayerlabs/genlayer-project-boilerplate/blob/main/contracts/football_bets.py) from the boilerplate repository:

```python
from genlayer import *

@allow_storage
class Bet:
    amount: u256
    choice: str
    timestamp: u256

class FootballBets(gl.Contract):
    bets: TreeMap[Address, TreeMap[str, Bet]]
    points: TreeMap[Address, u256]

    def __init__(self):
        self.bets = TreeMap()
        self.points = TreeMap()

    @gl.public.write
    def place_bet(self, match_id: str, amount: u256, choice: str):
        user = gl.message.sender_address
        user_bets = self.bets.get(user, TreeMap())
        user_bets[match_id] = Bet(
            amount=amount,
            choice=choice,
            timestamp=gl.vm.now()
        )
        self.bets[user] = user_bets
        self.points[user] = self.points.get(user, u256(0)) + u256(1)

```

The nested `TreeMap[str, Bet]` structure enables efficient per-user, per-match bet tracking while maintaining full determinism.

## Workarounds for Unsupported Patterns

Standard Python `list` cannot be stored directly in a `TreeMap`. The boilerplate demonstrates a JSON serialization pattern in [`contracts/PatternTest.py`](https://github.com/genlayerlabs/genlayer-project-boilerplate/blob/main/contracts/PatternTest.py):

```python
import json
from genlayer import *

class ListWrapper(gl.Contract):
    data: TreeMap[str, str]  # JSON-encoded lists

    def __init__(self):
        self.data = TreeMap()

    @gl.public.write
    def store_list(self, key: str, values: list[str]):
        self.data[key] = json.dumps(values)

    @gl.public.view
    def retrieve_list(self, key: str) -> list[str]:
        return json.loads(self.data.get(key, "[]"))

```

This approach trades some gas efficiency for flexibility when true nested collections are required.

## Complete Storage Type Reference

| Type | Mutability | Use Case | Source Reference |
|------|-----------|----------|----------------|
| `TreeMap[K,V]` | Mutable | Mappings with ordered iteration | [`CLAUDE.md`](https://github.com/genlayerlabs/genlayer-project-boilerplate/blob/main/CLAUDE.md) line 72 |
| `DynArray[T]` | Mutable | Variable-length sequences | [`CLAUDE.md`](https://github.com/genlayerlabs/genlayer-project-boilerplate/blob/main/CLAUDE.md) line 72 |
| `Array[T]` | Fixed-size | Compile-time bounded collections | [`CLAUDE.md`](https://github.com/genlayerlabs/genlayer-project-boilerplate/blob/main/CLAUDE.md) line 72 |
| `u256` / `i256` | Value types | All numeric computation | [`CLAUDE.md`](https://github.com/genlayerlabs/genlayer-project-boilerplate/blob/main/CLAUDE.md) line 72 |
| `@allow_storage` classes | Depends on fields | Domain-specific structs | [`contracts/football_bets.py`](https://github.com/genlayerlabs/genlayer-project-boilerplate/blob/main/contracts/football_bets.py) |

## Summary

- **Five storage types** are permitted in GenLayer intelligent contracts: `TreeMap`, `DynArray`, `Array`, `u256`/`i256`, and `@allow_storage` classes.
- **Native Python containers** (`dict`, `list`, `set`) are rejected by the GenVM linter to ensure deterministic execution.
- **Custom structs** require the `@allow_storage` decorator and may only contain other allowed types.
- **Nested structures** like `TreeMap[Address, TreeMap[str, Bet]]` are fully supported as shown in [`contracts/football_bets.py`](https://github.com/genlayerlabs/genlayer-project-boilerplate/blob/main/contracts/football_bets.py).
- **Serialization workarounds** enable storing complex data when direct container nesting is insufficient.

## Frequently Asked Questions

### What happens if I use a Python list in a GenLayer contract?

The GenVM linter will reject the contract during compilation. Standard Python `list` produces nondeterministic memory layouts that could cause consensus failures across validator nodes. Use `DynArray` for dynamic collections or `Array` for fixed-size needs.

### Can I nest multiple storage types together?

Yes. The `FootballBets` example in [`contracts/football_bets.py`](https://github.com/genlayerlabs/genlayer-project-boilerplate/blob/main/contracts/football_bets.py) demonstrates `TreeMap[Address, TreeMap[str, Bet]]` with a custom `@allow_storage` class at the deepest level. Arbitrary nesting of allowed types is permitted.

### How do I store a variable-length list inside a TreeMap?

GenLayer does not support direct `TreeMap[K, list[V]]` storage. Serialize the list to JSON (or another deterministic format) and store as `TreeMap[K, str]` instead, as shown in [`contracts/PatternTest.py`](https://github.com/genlayerlabs/genlayer-project-boilerplate/blob/main/contracts/PatternTest.py). Deserialize when reading.

### Is there a size limit for DynArray or TreeMap?

The analysis does not specify explicit size limits. Practical limits are determined by gas costs for operations and the deterministic execution timeout in GenVM. For unbounded growth, consider pagination patterns or off-chain data with on-chain hashes.