NEAR Smart Contracts · 2 min read
Storage and Collections
When to use native Rust collections versus near_sdk::store (IterableMap, LookupMap, Vector), and why every collection needs a unique prefix.
Contract state is a key/value trie. If you put a big HashMap on the contract struct, NEAR loads the entire map on every call. Persistent collections in near_sdk::store split data across many storage keys and load only what you touch.
Native vs SDK
Use a native Vec or HashMap when the collection stays small (roughly under 100 entries) and you need all of it at once. Use an SDK collection when the set can grow.
| Type | Module | Iterable | Best for |
|---|---|---|---|
LookupMap | near_sdk::store | No | Point lookups, lowest storage |
IterableMap | near_sdk::store | Yes | Maps you need to list or paginate |
LookupSet / IterableSet | near_sdk::store | Set only / yes | Membership |
Vector | near_sdk::store | Yes | Ordered lists |
UnorderedMap in near_sdk::store is deprecated; prefer IterableMap.
Prefixes and lazy writes
Every collection is created with a unique prefix. That prefix namespaces its keys so two maps cannot collide. Most store collections cache writes in memory and flush them when the collection is dropped at the end of the call (you can also call flush()).
rust
use near_sdk::{near, store::{IterableMap, LookupMap, Vector}};
#[near(contract_state)]
pub struct Contract {
scores: IterableMap<String, u32>,
aliases: LookupMap<String, String>,
events: Vector<String>,
}
impl Default for Contract {
fn default() -> Self {
Self {
scores: IterableMap::new(b"s"),
aliases: LookupMap::new(b"a"),
events: Vector::new(b"e"),
}
}
}
#[near]
impl Contract {
pub fn set_score(&mut self, account: String, score: u32) {
self.scores.insert(account, score);
}
pub fn get_score(&self, account: String) -> Option<u32> {
self.scores.get(&account).copied()
}
pub fn list_scores(&self, from_index: u32, limit: u32) -> Vec<(&String, &u32)> {
self.scores.iter().skip(from_index as usize).take(limit as usize).collect()
}
}For a view method, returning Option<&u32> or a collected Vec is fine. Do not return the collection itself.
Storage still costs 1 NEAR per 100 KB (env::storage_byte_cost()). Charge the caller or use NEP-145. The holder-only “Storage Staking Deep Dive” lesson walks through measure-and-refund in more detail.
Exercise
Sketch a contract state with an IterableMap of account → score. Write down the prefix you would use and a view method that returns a page of scores.
Saved in this browser.