#[storage]Expand description
Storage macros and traits for the key-value store.
§#[storage] / #[derive(Storage)]
The storage attribute macro is shorthand for
#[derive(Storage)].
Deriving Storage generates From<Keypath> for the struct, assigning a
sub-keypath to each field.
All fields must be SDK storage types. Plain data must be wrapped in
Value<T> to make the persistence model explicit.
§Storage types
| Type | Description |
|---|---|
Value<T> | Single XDR-serializable value |
Balance | Non-negative, zero-defaulting i128 amount (0..=i128::MAX) with checked and lazy increase/decrease; the type to reach for first for balances, allowances, and supply |
NNInt | i128 counter whose signed increments merge across concurrent transactions; the floor is enforced at commit (see its docs for the set/inc/strict_inc rules) |
CapacityConstraint | Block-wide linear limit that concurrent transactions consume from |
Bytestring | Variable-length byte blob |
RCQ<T> | Retrocausal queue: inserts commute, consumes are sequential |
Map<K, V> | Key-addressed collection (entries not enumerable) |
Vector<S> | Index-addressed, sparse-capable sequence |
Array<S, N> | Fixed-length sequence of N slots; no stored length |
Node<T> | Nested storage struct used inside collections |
§Common patterns
§Single values
Use Value<T> for ordinary stored fields.
Value::set() writes immediately to the storage delta for the current frame.
Value::load_mut() returns an auto-flushing edit guard: the updated value is
written back when the guard is dropped.
§Maps
Map<K, V> stores independently addressed entries.
Entries may be absent; at() and at_mut() return storage-slot guards, not
references into an in-memory collection.
§Vectors
Vector<S> tracks an in-bounds extent with
Vector::len(). Individual slots may still be
empty if their backing storage has been deleted, so vectors are sparse-capable.
Preferred append path:
Vector::push_with()constructs the new slot, lets you initialize it, then increments len.
Low-level append path:
Vector::push_empty_slot()increments len immediately and returns the new slot handle.
§Fixed-length arrays
Array<S, N> addresses element i at the slot
Map<u32, S> would use for key i, but knows its length at compile time:
at()/at_mut() are bounds-checked without a storage read, and the array can
be iterated and deleted. Every element may be unset. Element keys are derived
on access, so the handle costs the same whatever N is.
§Nested structs in collections
Collections store storage types, not plain structs. For a nested storage struct
inside a Map, Vector or Array, wrap it in Node<T>:
#[derive(Storage)]
struct Inner {
amount: Value<u64>,
}
#[derive(Storage)]
struct State {
inners: Vector<Node<Inner>>,
}§Deletable trait
Deletable marks storage types whose data can be
fully deleted. It provides three methods:
delete(&mut self): delete using the keypath’s own locking semanticsdelete_exclusive(&mut self): delete with an exclusive lockdelete_internal(&mut self, exclusive: bool): low-level propagation hook used by derived impls
§Which types are Deletable?
| Type | Deletable? | Notes |
|---|---|---|
NNInt | Yes | |
Balance | Yes | |
CapacityConstraint | Yes | |
Value<T> | Yes | |
Bytestring | Yes | |
RCQ<T> | Yes | Deletion cost scales with the queue’s size |
Node<T> | When T: Deletable | |
Vector<S> | When S: Deletable | |
Array<S, N> | When S: Deletable | Deletes all N elements |
Map<K, V> | No | Cannot enumerate entries |
§#[derive(Deletable)]
Opt-in derive macro. Generates a Deletable impl that calls
delete_internal() on every field.
If any field’s type does not implement Deletable, the derive produces a
compile error at the struct definition, similar to deriving Clone for a
struct containing a non-Clone field.
#[storage]
#[derive(Deletable)]
struct Counters {
a: NNInt,
b: Value<u64>,
}
// Counters::delete() will delete both `a` and `b`.Structs containing Map fields cannot derive Deletable:
#[storage]
struct Registry {
entries: Map<Address, Value<u64>>,
total: NNInt,
}
// #[derive(Deletable)] on Registry would fail:
// Map<_, _> does not implement Deletable.Usage examples are in the top-level documentation.
Mark a struct as contract storage: generates From<Keypath> so each
field is bound to a storage slot derived from the struct’s keypath.
Works on named-field structs (fields must themselves be storage
types like NNInt, Map, Value, or nested storage structs) and
on unit structs (struct Token;) for contracts that keep all state
behind raw storage keys.
Accepts an optional domain = "..." argument to override the default
domain (the struct’s bare identifier name).