Skip to main content

Types of Object Ownership

Every object has an owner that determines who can use it in transactions and whether the object is versioned on the fastpath or through consensus. The ownership type you choose affects transaction latency, concurrency, and the security model your smart contract must enforce.

Ownership typeAccess modelVersioning pathTypical latency
Address-ownedA single address can use the object.FastpathLowest (no consensus needed)
SharedAny address can use the object, subject to Move checks.ConsensusHigher (consensus ordering required)
ImmutableAny address can read the object; no one can mutate it.Fixed after it becomes immutableLowest (read-only, no versioning)
WrappedOnly accessible through the object that wraps it.Depends on the wrapperDepends on the wrapper
Consensus-address owned / partyA single address owns the object, but the object is sequenced by consensus.ConsensusHigher (consensus sequencing)

Choosing an ownership type

Choose the ownership type based on your access pattern.

  • Use address-owned objects when a single user owns and controls the object (for example, a user's NFT, a personal wallet, or a capability token). Address-owned objects skip consensus, so transactions against them have the lowest latency.
  • Use shared objects when multiple users need to read and write the same object (for example, a marketplace, a liquidity pool, or a game board). Shared objects go through consensus, which adds latency but enables concurrent access. Contention on a single shared object can reduce transaction throughput, so minimize the number of transactions that write to the same shared object in the same checkpoint (Security Best Practices).
  • Use immutable objects for data that never changes after creation (for example, published packages, configuration constants, or reference data). Immutable objects have no versioning overhead and any transaction can read them without consensus.
  • Use wrapped objects when an object should only be accessible through its parent (for example, a ticket inside an envelope, or inventory items inside a character). See Wrapped Objects for details.

Address-owned

Use address-owned objects when a single user owns and controls the object (for example, a user's NFT, a personal wallet, or a capability token). Address-owned objects skip consensus, so transactions against them have the lowest latency.

Shared

Use shared objects when multiple users need to read and write the same object (for example, a marketplace, a liquidity pool, or a game board). Shared objects go through consensus, which adds latency but enables concurrent access. Contention on a single shared object can reduce transaction throughput, so minimize the number of transactions that write to the same shared object in the same checkpoint.

Immutable

Use immutable objects for data that never changes after creation (for example, published packages, configuration constants, or reference data). Immutable objects have no versioning overhead and any transaction can read them without consensus.

Wrapped

Use wrapped objects when an object should only be accessible through its parent (for example, a ticket inside an envelope, or inventory items inside a character). See Wrapped Objects for details.

Party

Use party objects when you want single-address ownership but need to allow multiple inflight transactions against the same object without fastpath locks. Party objects are sequenced by consensus but owned by a single address.

APIs expose consensus-address-owned objects with a ConsensusAddressOwner owner variant. Party objects are the public Move-facing way to create this ownership form with sui::party::Party and sui::transfer::party_transfer or sui::transfer::public_party_transfer.

caution

Anyone can submit a transaction that references a shared object. Shared-object access is not restricted by ownership, so secure it in Move with explicit authorization checks (such as a capability argument, a tx_context::sender() check, or validating object ownership). Do not assume that referencing a shared object implies the caller is authorized. See Access control.