What is the Publisher object on Sui?
November 5, 2026
The Publisher object, defined in sui::package, proves that its holder published a particular module and therefore has authority over the types defined there. You claim it once, in the module's init function, by handing over the module's one-time witness to package::claim. Framework features that configure behaviour for a type you own, such as Object Display and Kiosk TransferPolicy, take &Publisher as proof.
Definition
module sui::package;
public struct Publisher has key, store {
id: UID,
package: String,
module_name: String,
}It stores the package address and module name as strings. Because it has key and store, it is a normal owned object: you can transfer it, keep it in another object, or burn it.
Claiming it
module book::hero;
use sui::package;
public struct Hero has key, store { id: UID }
/// One-time witness for this module.
public struct HERO has drop {}
fun init(otw: HERO, ctx: &mut TxContext) {
// Claim and send to the publisher in one call:
package::claim_and_keep(otw, ctx);
}claim_and_keep is shorthand for transfer::public_transfer(package::claim(otw, ctx), ctx.sender()). Use plain claim if you want to store the Publisher somewhere else or use it immediately, for example to create a Display<Hero> in the same init.
Since the OTW exists only once per module, there can be only one Publisher per module, but a package with several modules can have several.
Checking authority
Publisher has two checks:
publisher.from_module<Hero>() // Hero is defined in this Publisher's module
publisher.from_package<Hero>() // Hero is defined in this Publisher's packageBoth compare against the type's original package ID, so a Publisher keeps working for types after a package upgrade. There are also published_package() and published_module() getters, and burn_publisher to destroy it.
Where it's required
- Display:
display::new<T>(pub: &Publisher, ctx)creates aDisplay<T>, which tells wallets and explorers how to render objects of typeT. - Kiosk:
transfer_policy::new<T>(pub: &Publisher, ctx)creates theTransferPolicy<T>that governs trades ofTin Kiosks.
Each of these functions checks internally that the Publisher is from the package that defines T, so a Publisher from one package can't configure another package's types.
Using it as an admin key
You can gate your own functions with &Publisher, but be careful: every published module can produce a Publisher, so the type alone proves nothing. Always check it:
const ENotAuthorized: u64 = 0;
public fun admin_action(pub: &Publisher, /* ... */) {
assert!(pub.from_module<Hero>(), ENotAuthorized);
// ...
}Forget the check and anyone holding any Publisher can call the function. For application permissions, a dedicated capability struct like AdminCap created in init is usually clearer and type-safe.
Gotchas
- Keep it safe. Whoever holds the
Publishercan create new Display and transfer policy objects for your types. Many teams store it with the deployer or a multisig address. - You can only claim it in
init, because that's the only place the OTW exists. If you published without claiming it, you can't get one later for that module. - In tests,
package::test_claim(otw, ctx)creates aPublisherwithout the OTW check.
Sources
- Publisher Authority, The Move Book
sui::packagesource, MystenLabs/suisui::packagereference, Sui documentation