Skip to main content

Object Display V2

danger

Object Display V2 will be available in Sui v1.68. You can check the release schedule to learn more about when v1.68 is available on Devnet, Testnet, and Mainnet.

All existing V1 displays will be migrated to V2 in a system snapshot migration. You don't need to do anything upfront; after the snapshot, you can claim the capability when you're ready (see Migration and claiming).

V1 end of life

Object Display V1 will be supported by RPCs that already have support for it (JSON-RPC, GraphQL) until the end of July 2026. After that, on-chain V1 display code will be decommissioned and will start aborting.

It is recommended to use the sui::display_registry APIs when creating display from Move code. For the intermediate phase, use the migrate_v1_to_v2 function to migrate a legacy display and receive the V2 Display<T> and DisplayCap<T>.

What's new in V2

Display V2 brings a richer templating model, improved rendering pipeline, and better tooling, including:

  • Collection access: Use vectors, sets, and maps directly in your display templates.

  • Dynamic field access: Reference dynamic fields on objects in your templates.

  • Object loading: Load and reference objects when resolving display.

  • GraphQL: Rich APIs to use display as a querying tool, not just for rendering.

Differences between V1 and V2

In V1, discovering the display for a type relied on events, for example, DisplayCreated<T>. Clients had to query historical events by type and infer which object(s) represented the display. This approach depends on historical event data, doesn't scale for full nodes that may not retain full history, and is a poor fit for RPC APIs like JSON-RPC, gRPC, and others that need a stable, cheap way to resolve "display for type T" without scanning events.

In V2, the display for type T has a single, deterministic ID derived from the global registry and the type. That ID can be computed offline without using events or history. RPCs can resolve "display for type T" by derivation only, which is sustainable for full nodes. This is the main gain for JSON-RPC and gRPC. GraphQL is less affected, as it maintains its own indexed state.

Structural change: N → 1, and derived

In Object Display V1, you could have N displays per type and had to use events to query them. In Object Display V2, there is only 1 per type and you get it by derivation.

V1V2
Displays per typeMultiple Display<T> could exist.Exactly one Display<T> per type T.
How you find Display<T>Query events by type; requires historical events.Offline derivation. Display<T> is a derived object from (DisplayRegistry UID, DisplayKey<T>). ID is computable from registry and type; no events, no scan.
IdentityUnpredictable (per creation tx).Deterministic. The same registry and same T result in the same display ID everywhere.

Migration and claiming

All V1 displays will be migrated to V2 in a system snapshot migration. After that, for each type the single V2 Display<T> exists with cap_id: none until the capability is claimed.

The capability can be claimed in either of two ways:

  • Publisher using claim_with_publisher: Use this if you hold the Publisher object. It proves type ownership via publisher.from_package<T>().

  • Legacy Display using claim: Use this if you hold the V1 Display<T> object. Pass it in; it is consumed and you receive the DisplayCap<T>.

Once claimed, the holder of DisplayCap<T> can update the display fields (set, unset, clear). Anyone who holds a V1 Display<T> can call delete_legacy(display, legacy) to burn their legacy object.