Can we load an object by ID during a move call?

Originally asked on Discord.

The short answer to this is “no” – address-owned, shared and immutable objects all need to be specified as inputs to entry functions, so it is not possible to load them dynamically by ID in the middle of a move call transaction.

However, Dynamic Fields can be loaded dynamically, so if you find yourself needing to load an object by its ID during a move call, a useful pattern is to add those objects as dynamic fields to an over-arching parent, which is passed in as entry function for access. The Bag collection type is an example of this pattern:

module example::dynamic_loading {
    use std::string::{Self, String};
    use sui::object_bag::{Self as obag, ObjectBag}; 
    use sui::object::{Self, ID, UID};
    use sui::tx_context::{Self, TxContext};
    struct Item has key, store {
        id: UID,
        label: String,

    struct Holder has key {
        id: UID,
        items: ObjectBag<Id, Item>,

    public entry fun add_item(holder: &mut Holder, item: Item) {
        obag::add<ID, Item>(
            &mut hold.items,

    public entry fun use_item(holder: &Holder, i: ID, j: ID, choice: bool) {
        let item = obag::borrow<ID, Item>(
            if (choice) { i } else { j },

        // use item: &Item