What are dynamic fields on Sui?
November 9, 2026
Dynamic fields let you attach extra data to an object at runtime, beyond the fields fixed in its struct definition. Each field is keyed by a name, which can be any value with copy, drop and store (an integer, a string, a struct), and holds a value of any type with store. You add, read and remove them through the object's UID using sui::dynamic_field. A field only costs gas when a transaction touches it, so a parent can hold a very large number of them without getting bigger itself.
Why they exist
Regular struct fields have three limits:
- The set of fields is fixed when you publish the module.
- Wrapping many objects inside one makes it large, and objects have a size limit.
- A
vector<T>holds one type only, so you can't keep a mixed collection in it.
Dynamic fields fix all three. They're also the building block for Table, Bag, ObjectTable, ObjectBag and LinkedTable.
Example
module example::profile;
use std::string::String;
use sui::dynamic_field as df;
public struct Profile has key {
id: UID,
}
/// Field-name type: one key per kind of data.
public struct BioKey has copy, drop, store {}
public fun new(ctx: &mut TxContext): Profile {
Profile { id: object::new(ctx) }
}
public fun set_bio(p: &mut Profile, bio: String) {
if (df::exists(&p.id, BioKey {})) {
*df::borrow_mut<BioKey, String>(&mut p.id, BioKey {}) = bio;
} else {
df::add(&mut p.id, BioKey {}, bio);
}
}
public fun bio(p: &Profile): &String {
df::borrow(&p.id, BioKey {})
}
public fun clear_bio(p: &mut Profile): String {
df::remove(&mut p.id, BioKey {})
}Only code that can get &mut UID can add or change fields. By keeping id private and exposing just the functions above, your module controls who can write.
The API
From sui::dynamic_field:
add(&mut UID, name, value): aborts if the field already existsborrow/borrow_mut(&UID, name): aborts if it's missing or has a different value typeremove(&mut UID, name): returns the valueexists(&UID, name)andexists_with_type<Name, Value>(&UID, name)remove_optreturns anOption, andreplaceswaps the value and returns the old one
exists_ and remove_if_exists still compile but are deprecated in favor of exists and remove_opt.
A field is identified by the parent ID, the type of the name and the name's value together. A field added with a vector<u8> name can't be read with a String name, even if the bytes are the same. That mismatch is the most common cause of EFieldDoesNotExist.
Abort codes
| Code | Constant | Meaning |
|---|---|---|
| 0 | EFieldAlreadyExists |
add on an existing name |
| 1 | EFieldDoesNotExist |
borrow or remove of a missing name |
| 2 | EFieldTypeMismatch |
name exists, value type differs |
| 3 | EBCSSerializationFailure |
name couldn't be serialized |
| 4 | ESharedObjectOperationNotSupported |
tried to add a shared object as a value |
Gotchas
- Deleting the parent orphans its fields. You can delete an object that still has dynamic fields, and those fields become unreachable forever. Remove them first, or use
Table/Bag. Those types count their entries, anddestroy_emptyaborts unless they're empty. - Objects stored with
dynamic_fieldare wrapped. They vanish from ID lookups in explorers and wallets. If they need to stay visible, usedynamic_object_field(see What is the difference between dynamic fields and dynamic object fields?). - Each field is its own object under the hood (a
Field<Name, Value>whose ID is derived from the parent and name), so each access counts as loading an object.
Reading dynamic fields offchain
With @mysten/sui v2:
const { dynamicFields, hasNextPage, cursor } = await client.listDynamicFields({
parentId: PROFILE_ID,
});
for (const f of dynamicFields) {
console.log(f.$kind, f.name.type, f.valueType, f.fieldId);
}getDynamicField({ parentId, name: { type, bcs } }) fetches one field by its BCS-encoded name. The CLI equivalent is sui client dynamic-field <PARENT_ID>, and GraphQL exposes dynamicFields on an object (see How do I query Sui with GraphQL?).
Sources
- Dynamic Fields, Sui documentation
- dynamic_field.move, Sui framework source
- Dynamic Fields, The Move Book