Skip to main content

Storage types

Smart contracts can persist data in the Stellar ledger using the storage interface (env.storage() in Soroban SDK). There are three types of storage available on the Stellar network: Every storage type can be thought of as a map from arbitrary keys to arbitrary values. The data is physically stored in the Stellar ledger. Every storage ‘map’ is completely independent from every other storage ‘map’. It is possible to store different data for the same key in every storage. For example, in temporary storage, key 123_u32 may have a value of 100_u32, while in persistent storage the same 123_u32 key may have a value of abcd. All the storage types have almost exactly the same functionality, besides the differences highlighted in the table above, specifically cost, behavior when TTL expires, and limit for the number of keys stored per contract.

A note on TTL

If you’re wondering what ‘TTL’ means, here is a quick intro on TTLs and state archival in Stellar. State archival is a special mechanism defined by the Stellar protocol that ensures that the active ledger state size doesn’t grow indefinitely. In simple terms, every stored contract data entry, as well as contract code (Wasm) entry, has a certain ‘time-to-live’ (TTL) assigned. TTL is just a number of ledgers for which the entry is considered to be ‘active’, and after that number of ledgers, the entry is considered to have TTL expired and thus no longer active. Different storage types handle TTL expiration differently: data will either be moved to the archive (‘cold’, off-chain storage), or automatically removed from the ledger (in case of temporary storage). The data stored in the archive can be restored on-chain later and thus become active again. TTL also may be extended however many times are necessary, for a fee. Read more about state archival here.

Persistent storage

This storage type is used for storing data on the network over an indefinitely long time period. For persistent storage, when the TTL reaches zero, the entry is moved to the archival storage. It can then be restored when needed — usually automatically, by including the entry in a transaction’s restore list (which transaction simulation typically populates for you), or manually using the RestoreFootprintOp operation. Persistent storage is the default storage type use-case-wise. Instance and temporary storage are only useful for the specific use cases described in the respective sections. Stellar protocol also uses persistent storage to store the contracts and their Wasm executables, so that they always can be accessed or restored. Examples of data that may be stored on persistent storage include user balances, token metadata, voting and governance decisions, and all data that need to either remain accessible forever, or until explicitly deleted. Let’s look at a contract for a loyalty points system where users can accumulate points and redeem them for rewards. Each user’s point balance will be stored in persistent storage.

Instance storage

Instance storage is a small, limited-size map attached to the contract instance. It is physically stored in the same ledger entry as the contract itself and shares TTL with it. Like persistent storage, instance storage stores data permanently. However, it has a few pros and cons compared to it:
  • Pro: Data TTL is tied to the contract instance, thus making state archival behavior much easier
  • Pro/Con: Data is loaded automatically together with the contract, thus reducing the transaction footprint size, but increasing the number of bytes read every time the contract is loaded (usually this still will result in a lower fee)
  • Con: The total size of all the keys and values in the instance storage is limited by the ledger entry size limit. See the current value of the limit on the Stellar Lab. The total number of keys supported is on the order of tens to hundreds depending on the underlying data size and the current network limit. The limit is set by validator vote, and the protocol only requires it to stay at or above a small fixed minimum, so it isn’t guaranteed to never decrease. Leave headroom rather than filling instance storage close to the current limit.
Instance storage is best suited for data that has a well-known size limit and is either very small, or is necessary for every contract invocation. For example, contract administrator entry (small and should be maintained together with the contract instance), or a token pair for a liquidity pool (necessary for almost every operation on a liquidity pool). Let’s look at additional functions for the loyalty points contract from the previous section, specifically the functions that define the contract admin and add points to the users:

Temporary storage

As the name implies, temporary storage stores data only for a certain time period, and then discards it automatically when TTL expires. Temporary entries are gone forever when their TTL expires. The benefit of temporary storage is the smaller cost and the ability to set a very low TTL, both of which result in lower rent fees compared to persistent storage. See the current information on the minimal lifetimes and rent fees on the Stellar Lab. Temporary storage is suitable for data that is only necessary for a relatively short and well-defined time period. ‘Well-defined’ here means that when creating an entry, the contract should be able to define its maximum necessary TTL.
While TTL for the temporary data can be extended, it is unsafe to rely on the extensions to preserve data. There is always a risk of losing temporary data. Only the TTL extension made when the entry is created is guaranteed to happen.
It is also unsafe to rely on an entry expiring as it can be extended by anyone. When a time bound has to be enforced, always include it in the data as well.Temporary storage is a cost optimization, it’s not a mechanism of enforcing any time-based invariants.
Temporary storage is best suited for easily replaceable data, or data that is only relevant within a certain time period. For example, oracle price feed data that is only relevant for a few minutes, or limited time authorizations such as token allowances, session tokens, auctions, timelocks, etc. Nonces for the Soroban signatures are also stored in the temporary storage, at least until the signature itself expires. Let’s look at how temporary storage may be implemented in a contract that runs auctions periodically, and users can place bids that are valid only until some user-defined time point: